Skip to content

Commit ac371d5

Browse files
Fix Adding Filter Relative to Custom Filter
Closes gh-9787
1 parent e601d96 commit ac371d5

File tree

4 files changed

+232
-3
lines changed

4 files changed

+232
-3
lines changed

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

Lines changed: 12 additions & 2 deletions
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.
@@ -112,8 +112,18 @@ final class FilterOrderRegistration {
112112
put(SwitchUserFilter.class, order.next());
113113
}
114114

115-
private void put(Class<? extends Filter> filter, int position) {
115+
/**
116+
* Register a {@link Filter} with its specific position. If the {@link Filter} was
117+
* already registered before, the position previously defined is not going to be
118+
* overriden
119+
* @param filter the {@link Filter} to register
120+
* @param position the position to associate with the {@link Filter}
121+
*/
122+
void put(Class<? extends Filter> filter, int position) {
116123
String className = filter.getName();
124+
if (this.filterToOrder.containsKey(className)) {
125+
return;
126+
}
117127
this.filterToOrder.put(className, position);
118128
}
119129

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
@@ -2566,6 +2566,7 @@ public HttpSecurity addFilterBefore(Filter filter, Class<? extends Filter> befor
25662566
private HttpSecurity addFilterAtOffsetOf(Filter filter, int offset, Class<? extends Filter> registeredFilter) {
25672567
int order = this.filterOrders.getOrder(registeredFilter) + offset;
25682568
this.filters.add(new OrderedFilter(filter, order));
2569+
this.filterOrders.put(filter.getClass(), order);
25692570
return this;
25702571
}
25712572

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: 144 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.
@@ -30,14 +30,18 @@
3030
import org.junit.Rule;
3131
import org.junit.Test;
3232

33+
import org.springframework.context.annotation.Bean;
3334
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
3435
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
3536
import org.springframework.security.config.test.SpringTestRule;
3637
import org.springframework.security.web.FilterChainProxy;
38+
import org.springframework.security.web.SecurityFilterChain;
3739
import org.springframework.security.web.access.ExceptionTranslationFilter;
3840
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
3941
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
42+
import org.springframework.security.web.context.SecurityContextPersistenceFilter;
4043
import org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter;
44+
import org.springframework.security.web.header.HeaderWriterFilter;
4145

4246
import static org.assertj.core.api.Assertions.assertThat;
4347

@@ -70,6 +74,46 @@ public void addFilterAtWhenSameFilterDifferentPlacesThenOrderCorrect() {
7074
ExceptionTranslationFilter.class);
7175
}
7276

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

88132
}
89133

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

@@ -129,4 +193,83 @@ protected void configure(HttpSecurity http) throws Exception {
129193

130194
}
131195

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

0 commit comments

Comments
 (0)