Skip to content

Commit 76d7a85

Browse files
Use modified classpath test support for tests that depend on the classpath
Issue gh-11347
1 parent 77dcc69 commit 76d7a85

File tree

4 files changed

+234
-122
lines changed

4 files changed

+234
-122
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/*
2+
* Copyright 2002-2022 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;
18+
19+
import java.util.List;
20+
21+
import org.junit.jupiter.api.BeforeEach;
22+
import org.junit.jupiter.api.Test;
23+
24+
import org.springframework.http.HttpMethod;
25+
import org.springframework.security.test.support.ClassPathExclusions;
26+
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
27+
import org.springframework.security.web.util.matcher.RequestMatcher;
28+
29+
import static org.assertj.core.api.Assertions.assertThat;
30+
31+
/**
32+
* Tests for {@link AbstractRequestMatcherRegistry} with no Spring MVC in the classpath
33+
*
34+
* @author Marcus Da Coregio
35+
*/
36+
@ClassPathExclusions("spring-webmvc-*.jar")
37+
public class AbstractRequestMatcherRegistryNoMvcTests {
38+
39+
private TestRequestMatcherRegistry matcherRegistry;
40+
41+
@BeforeEach
42+
public void setUp() {
43+
this.matcherRegistry = new TestRequestMatcherRegistry();
44+
}
45+
46+
@Test
47+
public void requestMatchersWhenPatternAndMvcNotPresentThenReturnAntPathRequestMatcherType() {
48+
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/path");
49+
assertThat(requestMatchers).isNotEmpty();
50+
assertThat(requestMatchers.size()).isEqualTo(1);
51+
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
52+
}
53+
54+
@Test
55+
public void requestMatchersWhenHttpMethodAndPatternAndMvcNotPresentThenReturnAntPathRequestMatcherType() {
56+
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers(HttpMethod.GET, "/path");
57+
assertThat(requestMatchers).isNotEmpty();
58+
assertThat(requestMatchers.size()).isEqualTo(1);
59+
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
60+
}
61+
62+
@Test
63+
public void requestMatchersWhenHttpMethodAndMvcNotPresentThenReturnAntPathMatcherType() {
64+
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers(HttpMethod.GET);
65+
assertThat(requestMatchers).isNotEmpty();
66+
assertThat(requestMatchers.size()).isEqualTo(1);
67+
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
68+
}
69+
70+
private static class TestRequestMatcherRegistry extends AbstractRequestMatcherRegistry<List<RequestMatcher>> {
71+
72+
@Override
73+
public List<RequestMatcher> mvcMatchers(String... mvcPatterns) {
74+
return null;
75+
}
76+
77+
@Override
78+
public List<RequestMatcher> mvcMatchers(HttpMethod method, String... mvcPatterns) {
79+
return null;
80+
}
81+
82+
@Override
83+
protected List<RequestMatcher> chainRequestMatchers(List<RequestMatcher> requestMatchers) {
84+
return requestMatchers;
85+
}
86+
87+
}
88+
89+
}

Diff for: config/src/test/java/org/springframework/security/config/annotation/web/AbstractRequestMatcherRegistryTests.java

+6-54
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@
1616

1717
package org.springframework.security.config.annotation.web;
1818

19-
import java.lang.reflect.Field;
20-
import java.lang.reflect.Modifier;
2119
import java.util.List;
2220

2321
import jakarta.servlet.DispatcherType;
@@ -43,6 +41,7 @@
4341
* Tests for {@link AbstractRequestMatcherRegistry}.
4442
*
4543
* @author Joe Grandja
44+
* @author Marcus Da Coregio
4645
*/
4746
public class AbstractRequestMatcherRegistryTests {
4847

@@ -61,6 +60,7 @@ public void setUp() {
6160
ApplicationContext context = mock(ApplicationContext.class);
6261
given(context.getBean(ObjectPostProcessor.class)).willReturn(NO_OP_OBJECT_POST_PROCESSOR);
6362
this.matcherRegistry.setApplicationContext(context);
63+
mockMvcIntrospector(true);
6464
}
6565

6666
@Test
@@ -113,70 +113,31 @@ public void dispatcherMatchersWhenPatternParamThenReturnAntPathRequestMatcherTyp
113113
}
114114

115115
@Test
116-
public void requestMatchersWhenPatternAndMvcPresentThenReturnMvcRequestMatcherType() throws Exception {
117-
mockMvcPresentClasspath(true);
118-
mockMvcIntrospector(true);
116+
public void requestMatchersWhenPatternAndMvcPresentThenReturnMvcRequestMatcherType() {
119117
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/path");
120118
assertThat(requestMatchers).isNotEmpty();
121119
assertThat(requestMatchers.size()).isEqualTo(1);
122120
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(MvcRequestMatcher.class);
123121
}
124122

125123
@Test
126-
public void requestMatchersWhenHttpMethodAndPatternAndMvcPresentThenReturnMvcRequestMatcherType() throws Exception {
127-
mockMvcPresentClasspath(true);
128-
mockMvcIntrospector(true);
124+
public void requestMatchersWhenHttpMethodAndPatternAndMvcPresentThenReturnMvcRequestMatcherType() {
129125
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers(HttpMethod.GET, "/path");
130126
assertThat(requestMatchers).isNotEmpty();
131127
assertThat(requestMatchers.size()).isEqualTo(1);
132128
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(MvcRequestMatcher.class);
133129
}
134130

135131
@Test
136-
public void requestMatchersWhenHttpMethodAndMvcPresentThenReturnMvcRequestMatcherType() throws Exception {
137-
mockMvcPresentClasspath(true);
138-
mockMvcIntrospector(true);
132+
public void requestMatchersWhenHttpMethodAndMvcPresentThenReturnMvcRequestMatcherType() {
139133
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers(HttpMethod.GET);
140134
assertThat(requestMatchers).isNotEmpty();
141135
assertThat(requestMatchers.size()).isEqualTo(1);
142136
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(MvcRequestMatcher.class);
143137
}
144138

145139
@Test
146-
public void requestMatchersWhenPatternAndMvcNotPresentThenReturnAntPathRequestMatcherType() throws Exception {
147-
mockMvcPresentClasspath(false);
148-
mockMvcIntrospector(false);
149-
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers("/path");
150-
assertThat(requestMatchers).isNotEmpty();
151-
assertThat(requestMatchers.size()).isEqualTo(1);
152-
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
153-
}
154-
155-
@Test
156-
public void requestMatchersWhenHttpMethodAndPatternAndMvcNotPresentThenReturnAntPathRequestMatcherType()
157-
throws Exception {
158-
mockMvcPresentClasspath(false);
159-
mockMvcIntrospector(false);
160-
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers(HttpMethod.GET, "/path");
161-
assertThat(requestMatchers).isNotEmpty();
162-
assertThat(requestMatchers.size()).isEqualTo(1);
163-
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
164-
}
165-
166-
@Test
167-
public void requestMatchersWhenHttpMethodAndMvcNotPresentThenReturnAntPathMatcherType() throws Exception {
168-
mockMvcPresentClasspath(false);
169-
mockMvcIntrospector(false);
170-
List<RequestMatcher> requestMatchers = this.matcherRegistry.requestMatchers(HttpMethod.GET);
171-
assertThat(requestMatchers).isNotEmpty();
172-
assertThat(requestMatchers.size()).isEqualTo(1);
173-
assertThat(requestMatchers.get(0)).isExactlyInstanceOf(AntPathRequestMatcher.class);
174-
}
175-
176-
@Test
177-
public void requestMatchersWhenMvcPresentInClassPathAndMvcIntrospectorBeanNotAvailableThenException()
178-
throws Exception {
179-
mockMvcPresentClasspath(true);
140+
public void requestMatchersWhenMvcPresentInClassPathAndMvcIntrospectorBeanNotAvailableThenException() {
180141
mockMvcIntrospector(false);
181142
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
182143
.isThrownBy(() -> this.matcherRegistry.requestMatchers("/path")).withMessageContaining(
@@ -188,15 +149,6 @@ private void mockMvcIntrospector(boolean isPresent) {
188149
given(context.containsBean("mvcHandlerMappingIntrospector")).willReturn(isPresent);
189150
}
190151

191-
private void mockMvcPresentClasspath(Object newValue) throws Exception {
192-
Field mvcPresentField = AbstractRequestMatcherRegistry.class.getDeclaredField("mvcPresent");
193-
mvcPresentField.setAccessible(true);
194-
Field modifiersField = Field.class.getDeclaredField("modifiers");
195-
modifiersField.setAccessible(true);
196-
modifiersField.setInt(mvcPresentField, mvcPresentField.getModifiers() & ~Modifier.FINAL);
197-
mvcPresentField.set(null, newValue);
198-
}
199-
200152
private static class TestRequestMatcherRegistry extends AbstractRequestMatcherRegistry<List<RequestMatcher>> {
201153

202154
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*
2+
* Copyright 2002-2022 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.configurers;
18+
19+
import jakarta.servlet.http.HttpServletResponse;
20+
import org.junit.jupiter.api.AfterEach;
21+
import org.junit.jupiter.api.BeforeEach;
22+
import org.junit.jupiter.api.Test;
23+
24+
import org.springframework.beans.factory.annotation.Autowired;
25+
import org.springframework.context.annotation.Bean;
26+
import org.springframework.context.annotation.Configuration;
27+
import org.springframework.context.annotation.Import;
28+
import org.springframework.mock.web.MockFilterChain;
29+
import org.springframework.mock.web.MockHttpServletRequest;
30+
import org.springframework.mock.web.MockHttpServletResponse;
31+
import org.springframework.mock.web.MockServletContext;
32+
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
33+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
34+
import org.springframework.security.test.support.ClassPathExclusions;
35+
import org.springframework.security.web.DefaultSecurityFilterChain;
36+
import org.springframework.security.web.FilterChainProxy;
37+
import org.springframework.security.web.SecurityFilterChain;
38+
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
39+
import org.springframework.web.bind.annotation.RequestMapping;
40+
import org.springframework.web.bind.annotation.RestController;
41+
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
42+
43+
import static org.assertj.core.api.Assertions.assertThat;
44+
45+
/**
46+
* @author Marcus Da Coregio
47+
*
48+
*/
49+
@ClassPathExclusions("spring-webmvc-*.jar")
50+
public class HttpSecuritySecurityMatchersNoMvcTests {
51+
52+
AnnotationConfigWebApplicationContext context;
53+
54+
MockHttpServletRequest request;
55+
56+
MockHttpServletResponse response;
57+
58+
MockFilterChain chain;
59+
60+
@Autowired
61+
FilterChainProxy springSecurityFilterChain;
62+
63+
@BeforeEach
64+
public void setup() throws Exception {
65+
this.request = new MockHttpServletRequest("GET", "");
66+
this.request.setMethod("GET");
67+
this.response = new MockHttpServletResponse();
68+
this.chain = new MockFilterChain();
69+
}
70+
71+
@AfterEach
72+
public void cleanup() {
73+
if (this.context != null) {
74+
this.context.close();
75+
}
76+
}
77+
78+
@Test
79+
public void securityMatcherWhenNoMvcThenAntMatcher() throws Exception {
80+
loadConfig(SecurityMatcherNoMvcConfig.class);
81+
this.request.setServletPath("/path");
82+
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
83+
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED);
84+
setup();
85+
this.request.setServletPath("/path.html");
86+
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
87+
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
88+
setup();
89+
this.request.setServletPath("/path/");
90+
this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain);
91+
assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
92+
assertThat(this.springSecurityFilterChain.getFilterChains())
93+
.extracting((c) -> ((DefaultSecurityFilterChain) c).getRequestMatcher())
94+
.hasOnlyElementsOfType(AntPathRequestMatcher.class);
95+
}
96+
97+
public void loadConfig(Class<?>... configs) {
98+
this.context = new AnnotationConfigWebApplicationContext();
99+
this.context.register(configs);
100+
this.context.setServletContext(new MockServletContext());
101+
this.context.refresh();
102+
this.context.getAutowireCapableBeanFactory().autowireBean(this);
103+
}
104+
105+
@EnableWebSecurity
106+
@Configuration
107+
@Import(HttpSecuritySecurityMatchersTests.UsersConfig.class)
108+
static class SecurityMatcherNoMvcConfig {
109+
110+
@Bean
111+
SecurityFilterChain appSecurity(HttpSecurity http) throws Exception {
112+
// @formatter:off
113+
http
114+
.securityMatcher("/path")
115+
.httpBasic().and()
116+
.authorizeHttpRequests()
117+
.anyRequest().denyAll();
118+
// @formatter:on
119+
return http.build();
120+
}
121+
122+
@RestController
123+
static class PathController {
124+
125+
@RequestMapping("/path")
126+
String path() {
127+
return "path";
128+
}
129+
130+
}
131+
132+
}
133+
134+
}

0 commit comments

Comments
 (0)