@ -16,7 +16,9 @@
@@ -16,7 +16,9 @@
package org.springframework.security.config.annotation.web.configuration ;
import java.util.ArrayList ;
import java.util.Arrays ;
import java.util.List ;
import java.util.concurrent.Callable ;
import javax.servlet.http.HttpServletRequest ;
@ -32,16 +34,22 @@ import org.springframework.beans.factory.BeanCreationException;
@@ -32,16 +34,22 @@ import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired ;
import org.springframework.context.annotation.Bean ;
import org.springframework.context.annotation.Configuration ;
import org.springframework.context.event.EventListener ;
import org.springframework.core.io.support.SpringFactoriesLoader ;
import org.springframework.mock.web.MockHttpSession ;
import org.springframework.security.access.AccessDeniedException ;
import org.springframework.security.authentication.AuthenticationEventPublisher ;
import org.springframework.security.authentication.TestingAuthenticationToken ;
import org.springframework.security.authentication.event.AbstractAuthenticationEvent ;
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent ;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent ;
import org.springframework.security.config.annotation.SecurityContextChangedListenerConfig ;
import org.springframework.security.config.annotation.web.builders.HttpSecurity ;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer ;
import org.springframework.security.config.test.SpringTestContext ;
import org.springframework.security.config.test.SpringTestContextExtension ;
import org.springframework.security.core.Authentication ;
import org.springframework.security.core.AuthenticationException ;
import org.springframework.security.core.context.SecurityContextHolderStrategy ;
import org.springframework.security.core.userdetails.User ;
import org.springframework.security.core.userdetails.UserDetails ;
@ -60,6 +68,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@@ -60,6 +68,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.mockito.Mockito.atLeastOnce ;
import static org.mockito.Mockito.verify ;
import static org.springframework.security.config.Customizer.withDefaults ;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin ;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication ;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf ;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user ;
@ -231,6 +240,48 @@ public class HttpSecurityConfigurationTests {
@@ -231,6 +240,48 @@ public class HttpSecurityConfigurationTests {
this . mockMvc . perform ( get ( "/login?logout" ) ) . andExpect ( status ( ) . isOk ( ) ) ;
}
@Test
public void loginWhenUsingDefaultThenAuthenticationEventPublished ( ) throws Exception {
this . spring
. register ( SecurityEnabledConfig . class , UserDetailsConfig . class , AuthenticationEventListenerConfig . class )
. autowire ( ) ;
AuthenticationEventListenerConfig . clearEvents ( ) ;
this . mockMvc . perform ( formLogin ( ) ) . andExpect ( status ( ) . is3xxRedirection ( ) ) ;
assertThat ( AuthenticationEventListenerConfig . EVENTS ) . isNotEmpty ( ) ;
assertThat ( AuthenticationEventListenerConfig . EVENTS ) . hasSize ( 1 ) ;
}
@Test
public void loginWhenUsingDefaultAndNoUserDetailsServiceThenAuthenticationEventPublished ( ) throws Exception {
this . spring
. register ( SecurityEnabledConfig . class , UserDetailsConfig . class , AuthenticationEventListenerConfig . class )
. autowire ( ) ;
AuthenticationEventListenerConfig . clearEvents ( ) ;
this . mockMvc . perform ( formLogin ( ) ) . andExpect ( status ( ) . is3xxRedirection ( ) ) ;
assertThat ( AuthenticationEventListenerConfig . EVENTS ) . isNotEmpty ( ) ;
assertThat ( AuthenticationEventListenerConfig . EVENTS ) . hasSize ( 1 ) ;
}
@Test
public void loginWhenUsingCustomAuthenticationEventPublisherThenAuthenticationEventPublished ( ) throws Exception {
this . spring . register ( SecurityEnabledConfig . class , UserDetailsConfig . class ,
CustomAuthenticationEventPublisherConfig . class ) . autowire ( ) ;
CustomAuthenticationEventPublisherConfig . clearEvents ( ) ;
this . mockMvc . perform ( formLogin ( ) ) . andExpect ( status ( ) . is3xxRedirection ( ) ) ;
assertThat ( CustomAuthenticationEventPublisherConfig . EVENTS ) . isNotEmpty ( ) ;
assertThat ( CustomAuthenticationEventPublisherConfig . EVENTS ) . hasSize ( 1 ) ;
}
@Test
public void loginWhenUsingCustomAuthenticationEventPublisherAndNoUserDetailsServiceThenAuthenticationEventPublished ( )
throws Exception {
this . spring . register ( SecurityEnabledConfig . class , CustomAuthenticationEventPublisherConfig . class ) . autowire ( ) ;
CustomAuthenticationEventPublisherConfig . clearEvents ( ) ;
this . mockMvc . perform ( formLogin ( ) ) . andExpect ( status ( ) . is3xxRedirection ( ) ) ;
assertThat ( CustomAuthenticationEventPublisherConfig . EVENTS ) . isNotEmpty ( ) ;
assertThat ( CustomAuthenticationEventPublisherConfig . EVENTS ) . hasSize ( 1 ) ;
}
@Test
public void configureWhenAuthorizeHttpRequestsBeforeAuthorizeRequestThenException ( ) {
assertThatExceptionOfType ( BeanCreationException . class )
@ -368,6 +419,55 @@ public class HttpSecurityConfigurationTests {
@@ -368,6 +419,55 @@ public class HttpSecurityConfigurationTests {
}
@Configuration
static class CustomAuthenticationEventPublisherConfig {
static List < Authentication > EVENTS = new ArrayList < > ( ) ;
static void clearEvents ( ) {
EVENTS . clear ( ) ;
}
@Bean
AuthenticationEventPublisher publisher ( ) {
return new AuthenticationEventPublisher ( ) {
@Override
public void publishAuthenticationSuccess ( Authentication authentication ) {
EVENTS . add ( authentication ) ;
}
@Override
public void publishAuthenticationFailure ( AuthenticationException exception ,
Authentication authentication ) {
EVENTS . add ( authentication ) ;
}
} ;
}
}
@Configuration
static class AuthenticationEventListenerConfig {
static List < AbstractAuthenticationEvent > EVENTS = new ArrayList < > ( ) ;
static void clearEvents ( ) {
EVENTS . clear ( ) ;
}
@EventListener
void onAuthenticationSuccessEvent ( AuthenticationSuccessEvent event ) {
EVENTS . add ( event ) ;
}
@EventListener
void onAuthenticationFailureEvent ( AbstractAuthenticationFailureEvent event ) {
EVENTS . add ( event ) ;
}
}
@RestController
static class BaseController {