|
1 | 1 | /*
|
2 |
| - * Copyright 2002-2020 the original author or authors. |
| 2 | + * Copyright 2002-2022 the original author or authors. |
3 | 3 | *
|
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 5 | * you may not use this file except in compliance with the License.
|
|
16 | 16 |
|
17 | 17 | package org.springframework.security.config.annotation.web.configuration;
|
18 | 18 |
|
| 19 | +import java.util.ArrayList; |
| 20 | +import java.util.List; |
19 | 21 | import java.util.concurrent.Callable;
|
20 | 22 |
|
21 | 23 | import javax.servlet.http.HttpServletRequest;
|
|
27 | 29 | import org.springframework.beans.factory.annotation.Autowired;
|
28 | 30 | import org.springframework.context.annotation.Bean;
|
29 | 31 | import org.springframework.context.annotation.Configuration;
|
| 32 | +import org.springframework.context.event.EventListener; |
30 | 33 | import org.springframework.mock.web.MockHttpSession;
|
31 | 34 | import org.springframework.security.access.AccessDeniedException;
|
| 35 | +import org.springframework.security.authentication.AuthenticationEventPublisher; |
32 | 36 | import org.springframework.security.authentication.TestingAuthenticationToken;
|
| 37 | +import org.springframework.security.authentication.event.AbstractAuthenticationEvent; |
| 38 | +import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent; |
| 39 | +import org.springframework.security.authentication.event.AuthenticationSuccessEvent; |
33 | 40 | import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
34 | 41 | import org.springframework.security.config.test.SpringTestContext;
|
35 | 42 | import org.springframework.security.config.test.SpringTestContextExtension;
|
| 43 | +import org.springframework.security.core.Authentication; |
| 44 | +import org.springframework.security.core.AuthenticationException; |
36 | 45 | import org.springframework.security.core.context.SecurityContextHolder;
|
37 | 46 | import org.springframework.security.core.userdetails.User;
|
38 | 47 | import org.springframework.security.core.userdetails.UserDetails;
|
|
48 | 57 |
|
49 | 58 | import static org.assertj.core.api.Assertions.assertThat;
|
50 | 59 | import static org.springframework.security.config.Customizer.withDefaults;
|
| 60 | +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin; |
51 | 61 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
|
52 | 62 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
53 | 63 | import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
|
@@ -200,6 +210,48 @@ public void loginWhenUsingDefaultsThenDefaultLogoutSuccessPageGenerated() throws
|
200 | 210 | this.mockMvc.perform(get("/login?logout")).andExpect(status().isOk());
|
201 | 211 | }
|
202 | 212 |
|
| 213 | + @Test |
| 214 | + public void loginWhenUsingDefaultThenAuthenticationEventPublished() throws Exception { |
| 215 | + this.spring |
| 216 | + .register(SecurityEnabledConfig.class, UserDetailsConfig.class, AuthenticationEventListenerConfig.class) |
| 217 | + .autowire(); |
| 218 | + AuthenticationEventListenerConfig.clearEvents(); |
| 219 | + this.mockMvc.perform(formLogin()).andExpect(status().is3xxRedirection()); |
| 220 | + assertThat(AuthenticationEventListenerConfig.EVENTS).isNotEmpty(); |
| 221 | + assertThat(AuthenticationEventListenerConfig.EVENTS).hasSize(1); |
| 222 | + } |
| 223 | + |
| 224 | + @Test |
| 225 | + public void loginWhenUsingDefaultAndNoUserDetailsServiceThenAuthenticationEventPublished() throws Exception { |
| 226 | + this.spring |
| 227 | + .register(SecurityEnabledConfig.class, UserDetailsConfig.class, AuthenticationEventListenerConfig.class) |
| 228 | + .autowire(); |
| 229 | + AuthenticationEventListenerConfig.clearEvents(); |
| 230 | + this.mockMvc.perform(formLogin()).andExpect(status().is3xxRedirection()); |
| 231 | + assertThat(AuthenticationEventListenerConfig.EVENTS).isNotEmpty(); |
| 232 | + assertThat(AuthenticationEventListenerConfig.EVENTS).hasSize(1); |
| 233 | + } |
| 234 | + |
| 235 | + @Test |
| 236 | + public void loginWhenUsingCustomAuthenticationEventPublisherThenAuthenticationEventPublished() throws Exception { |
| 237 | + this.spring.register(SecurityEnabledConfig.class, UserDetailsConfig.class, |
| 238 | + CustomAuthenticationEventPublisherConfig.class).autowire(); |
| 239 | + CustomAuthenticationEventPublisherConfig.clearEvents(); |
| 240 | + this.mockMvc.perform(formLogin()).andExpect(status().is3xxRedirection()); |
| 241 | + assertThat(CustomAuthenticationEventPublisherConfig.EVENTS).isNotEmpty(); |
| 242 | + assertThat(CustomAuthenticationEventPublisherConfig.EVENTS).hasSize(1); |
| 243 | + } |
| 244 | + |
| 245 | + @Test |
| 246 | + public void loginWhenUsingCustomAuthenticationEventPublisherAndNoUserDetailsServiceThenAuthenticationEventPublished() |
| 247 | + throws Exception { |
| 248 | + this.spring.register(SecurityEnabledConfig.class, CustomAuthenticationEventPublisherConfig.class).autowire(); |
| 249 | + CustomAuthenticationEventPublisherConfig.clearEvents(); |
| 250 | + this.mockMvc.perform(formLogin()).andExpect(status().is3xxRedirection()); |
| 251 | + assertThat(CustomAuthenticationEventPublisherConfig.EVENTS).isNotEmpty(); |
| 252 | + assertThat(CustomAuthenticationEventPublisherConfig.EVENTS).hasSize(1); |
| 253 | + } |
| 254 | + |
203 | 255 | @RestController
|
204 | 256 | static class NameController {
|
205 | 257 |
|
@@ -270,6 +322,55 @@ UserDetailsService userDetailsService() {
|
270 | 322 |
|
271 | 323 | }
|
272 | 324 |
|
| 325 | + @Configuration |
| 326 | + static class CustomAuthenticationEventPublisherConfig { |
| 327 | + |
| 328 | + static List<Authentication> EVENTS = new ArrayList<>(); |
| 329 | + |
| 330 | + static void clearEvents() { |
| 331 | + EVENTS.clear(); |
| 332 | + } |
| 333 | + |
| 334 | + @Bean |
| 335 | + AuthenticationEventPublisher publisher() { |
| 336 | + return new AuthenticationEventPublisher() { |
| 337 | + |
| 338 | + @Override |
| 339 | + public void publishAuthenticationSuccess(Authentication authentication) { |
| 340 | + EVENTS.add(authentication); |
| 341 | + } |
| 342 | + |
| 343 | + @Override |
| 344 | + public void publishAuthenticationFailure(AuthenticationException exception, |
| 345 | + Authentication authentication) { |
| 346 | + EVENTS.add(authentication); |
| 347 | + } |
| 348 | + }; |
| 349 | + } |
| 350 | + |
| 351 | + } |
| 352 | + |
| 353 | + @Configuration |
| 354 | + static class AuthenticationEventListenerConfig { |
| 355 | + |
| 356 | + static List<AbstractAuthenticationEvent> EVENTS = new ArrayList<>(); |
| 357 | + |
| 358 | + static void clearEvents() { |
| 359 | + EVENTS.clear(); |
| 360 | + } |
| 361 | + |
| 362 | + @EventListener |
| 363 | + void onAuthenticationSuccessEvent(AuthenticationSuccessEvent event) { |
| 364 | + EVENTS.add(event); |
| 365 | + } |
| 366 | + |
| 367 | + @EventListener |
| 368 | + void onAuthenticationFailureEvent(AbstractAuthenticationFailureEvent event) { |
| 369 | + EVENTS.add(event); |
| 370 | + } |
| 371 | + |
| 372 | + } |
| 373 | + |
273 | 374 | @RestController
|
274 | 375 | static class BaseController {
|
275 | 376 |
|
|
0 commit comments