Skip to content

Commit 751b558

Browse files
committed
TestOneTimeTokenGenerationSuccessHandler.lastToken to non-static variable
Previously there were race conditions on the static member lastToken of TestOneTimeTokenGenerationSuccessHandler. This is because the tests run in parallel and one test may override the other tests lastToken and thus make the assertion on it incorrect. This commit changes lastToken to be a non-static variable to ensure that each test has it's own lastToken for asserting the expected value. Closes gh-16471
1 parent d97e01d commit 751b558

File tree

2 files changed

+60
-23
lines changed

2 files changed

+60
-23
lines changed

config/src/test/java/org/springframework/security/config/annotation/web/configurers/ott/OneTimeTokenLoginConfigurerTests.java

+35-11
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ void oneTimeTokenWhenCorrectTokenThenCanAuthenticate() throws Exception {
7272
this.mvc.perform(post("/ott/generate").param("username", "user").with(csrf()))
7373
.andExpectAll(status().isFound(), redirectedUrl("/login/ott"));
7474

75-
String token = TestOneTimeTokenGenerationSuccessHandler.lastToken.getTokenValue();
75+
String token = getLastToken().getTokenValue();
7676

7777
this.mvc.perform(post("/login/ott").param("token", token).with(csrf()))
7878
.andExpectAll(status().isFound(), redirectedUrl("/"), authenticated());
@@ -84,7 +84,7 @@ void oneTimeTokenWhenDifferentAuthenticationUrlsThenCanAuthenticate() throws Exc
8484
this.mvc.perform(post("/generateurl").param("username", "user").with(csrf()))
8585
.andExpectAll(status().isFound(), redirectedUrl("/redirected"));
8686

87-
String token = TestOneTimeTokenGenerationSuccessHandler.lastToken.getTokenValue();
87+
String token = getLastToken().getTokenValue();
8888

8989
this.mvc.perform(post("/loginprocessingurl").param("token", token).with(csrf()))
9090
.andExpectAll(status().isFound(), redirectedUrl("/authenticated"), authenticated());
@@ -96,7 +96,7 @@ void oneTimeTokenWhenCorrectTokenUsedTwiceThenSecondTimeFails() throws Exception
9696
this.mvc.perform(post("/ott/generate").param("username", "user").with(csrf()))
9797
.andExpectAll(status().isFound(), redirectedUrl("/login/ott"));
9898

99-
String token = TestOneTimeTokenGenerationSuccessHandler.lastToken.getTokenValue();
99+
String token = getLastToken().getTokenValue();
100100

101101
this.mvc.perform(post("/login/ott").param("token", token).with(csrf()))
102102
.andExpectAll(status().isFound(), redirectedUrl("/"), authenticated());
@@ -194,25 +194,37 @@ Please provide it as a bean or pass it to the oneTimeTokenLogin() DSL.
194194
""");
195195
}
196196

197+
private OneTimeToken getLastToken() {
198+
OneTimeToken lastToken = this.spring.getContext()
199+
.getBean(TestOneTimeTokenGenerationSuccessHandler.class).lastToken;
200+
return lastToken;
201+
}
202+
197203
@Configuration(proxyBeanMethods = false)
198204
@EnableWebSecurity
199205
@Import(UserDetailsServiceConfig.class)
200206
static class OneTimeTokenDefaultConfig {
201207

202208
@Bean
203-
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
209+
SecurityFilterChain securityFilterChain(HttpSecurity http,
210+
OneTimeTokenGenerationSuccessHandler ottSuccessHandler) throws Exception {
204211
// @formatter:off
205212
http
206213
.authorizeHttpRequests((authz) -> authz
207214
.anyRequest().authenticated()
208215
)
209216
.oneTimeTokenLogin((ott) -> ott
210-
.tokenGenerationSuccessHandler(new TestOneTimeTokenGenerationSuccessHandler())
217+
.tokenGenerationSuccessHandler(ottSuccessHandler)
211218
);
212219
// @formatter:on
213220
return http.build();
214221
}
215222

223+
@Bean
224+
TestOneTimeTokenGenerationSuccessHandler ottSuccessHandler() {
225+
return new TestOneTimeTokenGenerationSuccessHandler();
226+
}
227+
216228
}
217229

218230
@Configuration(proxyBeanMethods = false)
@@ -221,22 +233,28 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
221233
static class OneTimeTokenDifferentUrlsConfig {
222234

223235
@Bean
224-
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
236+
SecurityFilterChain securityFilterChain(HttpSecurity http,
237+
OneTimeTokenGenerationSuccessHandler ottSuccessHandler) throws Exception {
225238
// @formatter:off
226239
http
227240
.authorizeHttpRequests((authz) -> authz
228241
.anyRequest().authenticated()
229242
)
230243
.oneTimeTokenLogin((ott) -> ott
231244
.tokenGeneratingUrl("/generateurl")
232-
.tokenGenerationSuccessHandler(new TestOneTimeTokenGenerationSuccessHandler("/redirected"))
245+
.tokenGenerationSuccessHandler(ottSuccessHandler)
233246
.loginProcessingUrl("/loginprocessingurl")
234247
.authenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/authenticated"))
235248
);
236249
// @formatter:on
237250
return http.build();
238251
}
239252

253+
@Bean
254+
TestOneTimeTokenGenerationSuccessHandler ottSuccessHandler() {
255+
return new TestOneTimeTokenGenerationSuccessHandler("/redirected");
256+
}
257+
240258
}
241259

242260
@Configuration(proxyBeanMethods = false)
@@ -245,20 +263,26 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
245263
static class OneTimeTokenFormLoginConfig {
246264

247265
@Bean
248-
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
266+
SecurityFilterChain securityFilterChain(HttpSecurity http,
267+
OneTimeTokenGenerationSuccessHandler ottSuccessHandler) throws Exception {
249268
// @formatter:off
250269
http
251270
.authorizeHttpRequests((authz) -> authz
252271
.anyRequest().authenticated()
253272
)
254273
.formLogin(Customizer.withDefaults())
255274
.oneTimeTokenLogin((ott) -> ott
256-
.tokenGenerationSuccessHandler(new TestOneTimeTokenGenerationSuccessHandler())
275+
.tokenGenerationSuccessHandler(ottSuccessHandler)
257276
);
258277
// @formatter:on
259278
return http.build();
260279
}
261280

281+
@Bean
282+
TestOneTimeTokenGenerationSuccessHandler ottSuccessHandler() {
283+
return new TestOneTimeTokenGenerationSuccessHandler();
284+
}
285+
262286
}
263287

264288
@Configuration(proxyBeanMethods = false)
@@ -282,7 +306,7 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
282306

283307
static class TestOneTimeTokenGenerationSuccessHandler implements OneTimeTokenGenerationSuccessHandler {
284308

285-
private static OneTimeToken lastToken;
309+
private OneTimeToken lastToken;
286310

287311
private final OneTimeTokenGenerationSuccessHandler delegate;
288312

@@ -297,7 +321,7 @@ static class TestOneTimeTokenGenerationSuccessHandler implements OneTimeTokenGen
297321
@Override
298322
public void handle(HttpServletRequest request, HttpServletResponse response, OneTimeToken oneTimeToken)
299323
throws IOException, ServletException {
300-
lastToken = oneTimeToken;
324+
this.lastToken = oneTimeToken;
301325
this.delegate.handle(request, response, oneTimeToken);
302326
}
303327

config/src/test/kotlin/org/springframework/security/config/annotation/web/OneTimeTokenLoginDslTests.kt

+25-12
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class OneTimeTokenLoginDslTests {
6969
.redirectedUrl("/login/ott")
7070
)
7171

72-
val token = TestOneTimeTokenGenerationSuccessHandler.lastToken?.tokenValue
72+
val token = getLastToken().tokenValue
7373

7474
this.mockMvc.perform(
7575
MockMvcRequestBuilders.post("/login/ott").param("token", token)
@@ -91,7 +91,7 @@ class OneTimeTokenLoginDslTests {
9191
)
9292
.andExpectAll(MockMvcResultMatchers.status().isFound(), MockMvcResultMatchers.redirectedUrl("/redirected"))
9393

94-
val token = TestOneTimeTokenGenerationSuccessHandler.lastToken?.tokenValue
94+
val token = getLastToken().tokenValue
9595

9696
this.mockMvc.perform(
9797
MockMvcRequestBuilders.post("/loginprocessingurl").param("token", token)
@@ -104,48 +104,64 @@ class OneTimeTokenLoginDslTests {
104104
)
105105
}
106106

107+
private fun getLastToken(): OneTimeToken {
108+
val lastToken: OneTimeToken = spring.context
109+
.getBean(TestOneTimeTokenGenerationSuccessHandler::class.java).lastToken!!
110+
return lastToken
111+
}
112+
107113
@Configuration
108114
@EnableWebSecurity
109115
@Import(UserDetailsServiceConfig::class)
110116
open class OneTimeTokenConfig {
111117

112118
@Bean
113-
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
119+
open fun securityFilterChain(http: HttpSecurity, ottSuccessHandler: OneTimeTokenGenerationSuccessHandler): SecurityFilterChain {
114120
// @formatter:off
115121
http {
116122
authorizeHttpRequests {
117123
authorize(anyRequest, authenticated)
118124
}
119125
oneTimeTokenLogin {
120-
oneTimeTokenGenerationSuccessHandler = TestOneTimeTokenGenerationSuccessHandler()
126+
oneTimeTokenGenerationSuccessHandler = ottSuccessHandler
121127
}
122128
}
123129
// @formatter:on
124130
return http.build()
125131
}
132+
133+
@Bean
134+
open fun ottSuccessHandler(): TestOneTimeTokenGenerationSuccessHandler {
135+
return TestOneTimeTokenGenerationSuccessHandler()
136+
}
126137
}
127138

128139
@EnableWebSecurity
129140
@Configuration(proxyBeanMethods = false)
130141
@Import(UserDetailsServiceConfig::class)
131142
open class OneTimeTokenDifferentUrlsConfig {
132143
@Bean
133-
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
144+
open fun securityFilterChain(http: HttpSecurity, ottSuccessHandler: OneTimeTokenGenerationSuccessHandler): SecurityFilterChain {
134145
// @formatter:off
135146
http {
136147
authorizeHttpRequests {
137148
authorize(anyRequest, authenticated)
138149
}
139150
oneTimeTokenLogin {
140151
tokenGeneratingUrl = "/generateurl"
141-
oneTimeTokenGenerationSuccessHandler = TestOneTimeTokenGenerationSuccessHandler("/redirected")
152+
oneTimeTokenGenerationSuccessHandler = ottSuccessHandler
142153
loginProcessingUrl = "/loginprocessingurl"
143154
authenticationSuccessHandler = SimpleUrlAuthenticationSuccessHandler("/authenticated")
144155
}
145156
}
146157
// @formatter:on
147158
return http.build()
148159
}
160+
161+
@Bean
162+
open fun ottSuccessHandler(): TestOneTimeTokenGenerationSuccessHandler {
163+
return TestOneTimeTokenGenerationSuccessHandler("/redirected")
164+
}
149165
}
150166

151167
@Configuration(proxyBeanMethods = false)
@@ -156,9 +172,10 @@ class OneTimeTokenLoginDslTests {
156172
InMemoryUserDetailsManager(PasswordEncodedUser.user(), PasswordEncodedUser.admin())
157173
}
158174

159-
private class TestOneTimeTokenGenerationSuccessHandler :
175+
class TestOneTimeTokenGenerationSuccessHandler :
160176
OneTimeTokenGenerationSuccessHandler {
161177
private val delegate: OneTimeTokenGenerationSuccessHandler
178+
var lastToken: OneTimeToken? = null
162179

163180
constructor() {
164181
this.delegate =
@@ -175,12 +192,8 @@ class OneTimeTokenLoginDslTests {
175192
}
176193

177194
override fun handle(request: HttpServletRequest, response: HttpServletResponse, oneTimeToken: OneTimeToken) {
178-
lastToken = oneTimeToken
195+
this.lastToken = oneTimeToken
179196
delegate.handle(request, response, oneTimeToken)
180197
}
181-
182-
companion object {
183-
var lastToken: OneTimeToken? = null
184-
}
185198
}
186199
}

0 commit comments

Comments
 (0)