Skip to content

Commit e16b88c

Browse files
Fix Adding Filter Relative to Custom Filter
Closes gh-9787
1 parent 0ad2d90 commit e16b88c

File tree

4 files changed

+226
-4
lines changed

4 files changed

+226
-4
lines changed

config/src/main/java/org/springframework/security/config/annotation/web/builders/FilterOrderRegistration.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2013 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -108,9 +108,19 @@ final class FilterOrderRegistration {
108108
put(SwitchUserFilter.class, order.next());
109109
}
110110

111-
private void put(Class<? extends Filter> filter, int position) {
111+
/**
112+
* Register a {@link Filter} with its specific position. If the {@link Filter} was
113+
* already registered before, the position previously defined is not going to be
114+
* overriden
115+
* @param filter the {@link Filter} to register
116+
* @param position the position to associate with the {@link Filter}
117+
*/
118+
void put(Class<? extends Filter> filter, int position) {
112119
String className = filter.getName();
113-
filterToOrder.put(className, position);
120+
if (this.filterToOrder.containsKey(className)) {
121+
return;
122+
}
123+
this.filterToOrder.put(className, position);
114124
}
115125

116126
/**

config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2604,6 +2604,7 @@ public HttpSecurity addFilterBefore(Filter filter,
26042604
private HttpSecurity addFilterAtOffsetOf(Filter filter, int offset, Class<? extends Filter> registeredFilter) {
26052605
int order = this.filterOrders.getOrder(registeredFilter) + offset;
26062606
this.filters.add(new OrderedFilter(filter, order));
2607+
this.filterOrders.put(filter.getClass(), order);
26072608
return this;
26082609
}
26092610

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* Copyright 2002-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.config.annotation.web.builders;
18+
19+
import java.io.IOException;
20+
21+
import javax.servlet.Filter;
22+
import javax.servlet.FilterChain;
23+
import javax.servlet.ServletException;
24+
import javax.servlet.ServletRequest;
25+
import javax.servlet.ServletResponse;
26+
27+
import org.junit.Test;
28+
29+
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
30+
31+
import static org.assertj.core.api.Assertions.assertThat;
32+
33+
public class FilterOrderRegistrationTests {
34+
35+
private final FilterOrderRegistration filterOrderRegistration = new FilterOrderRegistration();
36+
37+
@Test
38+
public void putWhenNewFilterThenInsertCorrect() {
39+
int position = 153;
40+
this.filterOrderRegistration.put(MyFilter.class, position);
41+
Integer order = this.filterOrderRegistration.getOrder(MyFilter.class);
42+
assertThat(order).isEqualTo(position);
43+
}
44+
45+
@Test
46+
public void putWhenCustomFilterAlreadyExistsThenDoesNotOverride() {
47+
int position = 160;
48+
this.filterOrderRegistration.put(MyFilter.class, position);
49+
this.filterOrderRegistration.put(MyFilter.class, 173);
50+
Integer order = this.filterOrderRegistration.getOrder(MyFilter.class);
51+
assertThat(order).isEqualTo(position);
52+
}
53+
54+
@Test
55+
public void putWhenPredefinedFilterThenDoesNotOverride() {
56+
int position = 100;
57+
Integer predefinedFilterOrderBefore = this.filterOrderRegistration.getOrder(ChannelProcessingFilter.class);
58+
this.filterOrderRegistration.put(MyFilter.class, position);
59+
Integer myFilterOrder = this.filterOrderRegistration.getOrder(MyFilter.class);
60+
Integer predefinedFilterOrderAfter = this.filterOrderRegistration.getOrder(ChannelProcessingFilter.class);
61+
assertThat(myFilterOrder).isEqualTo(position);
62+
assertThat(predefinedFilterOrderAfter).isEqualTo(predefinedFilterOrderBefore).isEqualTo(position);
63+
}
64+
65+
static class MyFilter implements Filter {
66+
67+
@Override
68+
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
69+
throws IOException, ServletException {
70+
filterChain.doFilter(servletRequest, servletResponse);
71+
}
72+
73+
}
74+
75+
}

config/src/test/java/org/springframework/security/config/annotation/web/builders/HttpSecurityAddFilterTest.java

Lines changed: 137 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -37,7 +37,9 @@
3737
import org.springframework.security.web.access.ExceptionTranslationFilter;
3838
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
3939
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
40+
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
4041
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
42+
import org.springframework.security.web.header.HeaderWriterFilter;
4143

4244
import static org.assertj.core.api.Assertions.assertThat;
4345

@@ -70,6 +72,46 @@ public void addFilterAtWhenSameFilterDifferentPlacesThenOrderCorrect() {
7072
ExceptionTranslationFilter.class);
7173
}
7274

75+
@Test
76+
public void addFilterAfterWhenAfterCustomFilterThenOrderCorrect() {
77+
this.spring.register(MyOtherFilterRelativeToMyFilterAfterConfig.class).autowire();
78+
79+
assertThatFilters().containsSubsequence(WebAsyncManagerIntegrationFilter.class, MyFilter.class,
80+
MyOtherFilter.class);
81+
}
82+
83+
@Test
84+
public void addFilterBeforeWhenBeforeCustomFilterThenOrderCorrect() {
85+
this.spring.register(MyOtherFilterRelativeToMyFilterBeforeConfig.class).autowire();
86+
87+
assertThatFilters().containsSubsequence(MyOtherFilter.class, MyFilter.class,
88+
WebAsyncManagerIntegrationFilter.class);
89+
}
90+
91+
@Test
92+
public void addFilterAtWhenAtCustomFilterThenOrderCorrect() {
93+
this.spring.register(MyOtherFilterRelativeToMyFilterAtConfig.class).autowire();
94+
95+
assertThatFilters().containsSubsequence(WebAsyncManagerIntegrationFilter.class, MyFilter.class,
96+
MyOtherFilter.class, SecurityContextPersistenceFilter.class);
97+
}
98+
99+
@Test
100+
public void addFilterBeforeWhenCustomFilterDifferentPlacesThenOrderCorrect() {
101+
this.spring.register(MyOtherFilterBeforeToMyFilterMultipleAfterConfig.class).autowire();
102+
103+
assertThatFilters().containsSubsequence(WebAsyncManagerIntegrationFilter.class, MyOtherFilter.class,
104+
MyFilter.class, ExceptionTranslationFilter.class);
105+
}
106+
107+
@Test
108+
public void addFilterBeforeAndAfterWhenCustomFiltersDifferentPlacesThenOrderCorrect() {
109+
this.spring.register(MyAnotherFilterRelativeToMyCustomFiltersMultipleConfig.class).autowire();
110+
111+
assertThatFilters().containsSubsequence(HeaderWriterFilter.class, MyFilter.class, MyOtherFilter.class,
112+
MyOtherFilter.class, MyAnotherFilter.class, MyFilter.class, ExceptionTranslationFilter.class);
113+
}
114+
73115
private ListAssert<Class<?>> assertThatFilters() {
74116
FilterChainProxy filterChain = this.spring.getContext().getBean(FilterChainProxy.class);
75117
List<Class<?>> filters = filterChain.getFilters("/").stream().map(Object::getClass)
@@ -87,6 +129,26 @@ public void doFilter(ServletRequest servletRequest, ServletResponse servletRespo
87129

88130
}
89131

132+
static class MyOtherFilter implements Filter {
133+
134+
@Override
135+
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
136+
throws IOException, ServletException {
137+
filterChain.doFilter(servletRequest, servletResponse);
138+
}
139+
140+
}
141+
142+
static class MyAnotherFilter implements Filter {
143+
144+
@Override
145+
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
146+
throws IOException, ServletException {
147+
filterChain.doFilter(servletRequest, servletResponse);
148+
}
149+
150+
}
151+
90152
@EnableWebSecurity
91153
static class MyFilterMultipleAfterConfig extends WebSecurityConfigurerAdapter {
92154

@@ -129,4 +191,78 @@ protected void configure(HttpSecurity http) throws Exception {
129191

130192
}
131193

194+
@EnableWebSecurity
195+
static class MyOtherFilterRelativeToMyFilterAfterConfig extends WebSecurityConfigurerAdapter {
196+
197+
@Override
198+
protected void configure(HttpSecurity http) throws Exception {
199+
// @formatter:off
200+
http
201+
.addFilterAfter(new MyFilter(), WebAsyncManagerIntegrationFilter.class)
202+
.addFilterAfter(new MyOtherFilter(), MyFilter.class);
203+
// @formatter:on
204+
}
205+
206+
}
207+
208+
@EnableWebSecurity
209+
static class MyOtherFilterRelativeToMyFilterBeforeConfig extends WebSecurityConfigurerAdapter {
210+
211+
@Override
212+
protected void configure(HttpSecurity http) throws Exception {
213+
// @formatter:off
214+
http
215+
.addFilterBefore(new MyFilter(), WebAsyncManagerIntegrationFilter.class)
216+
.addFilterBefore(new MyOtherFilter(), MyFilter.class);
217+
// @formatter:on
218+
}
219+
220+
}
221+
222+
@EnableWebSecurity
223+
static class MyOtherFilterRelativeToMyFilterAtConfig extends WebSecurityConfigurerAdapter {
224+
225+
@Override
226+
protected void configure(HttpSecurity http) throws Exception {
227+
// @formatter:off
228+
http
229+
.addFilterAt(new MyFilter(), WebAsyncManagerIntegrationFilter.class)
230+
.addFilterAt(new MyOtherFilter(), MyFilter.class);
231+
// @formatter:on
232+
}
233+
234+
}
235+
236+
@EnableWebSecurity
237+
static class MyOtherFilterBeforeToMyFilterMultipleAfterConfig extends WebSecurityConfigurerAdapter {
238+
239+
@Override
240+
protected void configure(HttpSecurity http) throws Exception {
241+
// @formatter:off
242+
http
243+
.addFilterAfter(new MyFilter(), WebAsyncManagerIntegrationFilter.class)
244+
.addFilterAfter(new MyFilter(), ExceptionTranslationFilter.class)
245+
.addFilterBefore(new MyOtherFilter(), MyFilter.class);
246+
// @formatter:on
247+
}
248+
249+
}
250+
251+
@EnableWebSecurity
252+
static class MyAnotherFilterRelativeToMyCustomFiltersMultipleConfig extends WebSecurityConfigurerAdapter {
253+
254+
@Override
255+
protected void configure(HttpSecurity http) throws Exception {
256+
// @formatter:off
257+
http
258+
.addFilterAfter(new MyFilter(), HeaderWriterFilter.class)
259+
.addFilterBefore(new MyOtherFilter(), ExceptionTranslationFilter.class)
260+
.addFilterAfter(new MyOtherFilter(), MyFilter.class)
261+
.addFilterAt(new MyAnotherFilter(), MyOtherFilter.class)
262+
.addFilterAfter(new MyFilter(), MyAnotherFilter.class);
263+
// @formatter:on
264+
}
265+
266+
}
267+
132268
}

0 commit comments

Comments
 (0)