Spring Security issue with securing URLs dynamically - spring

I'm using Spring Security via Spring Boot 1.59 and am having an issue securing URLs dynamically
Below is my configure method:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
//.antMatchers("/home").access("hasAnyRole('ROLE_USER','ROLE_ADMIN')")
//.antMatchers("/home3").access("hasRole('ROLE_ADMIN')")
.and()
.formLogin().loginPage("/login").permitAll()
.loginProcessingUrl("/myLogin")
.usernameParameter("my_username").passwordParameter("my_password")
.defaultSuccessUrl("/home")
.and()
.logout()
.logoutUrl("/myLogout")
.logoutSuccessUrl("/login?logout")
.and()
.exceptionHandling().accessDeniedPage("/403")
.and()
.csrf().disable();
}
I have a custom FilterInvocationSecurityMetadataSource as below:
#Component
public class CustomFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource
{
protected Logger log = Logger.getLogger(CustomFilterInvocationSecurityMetadataSource.class.getName());
#Override
public Collection<ConfigAttribute> getAttributes(Object object)
{
FilterInvocation fi = (FilterInvocation) object;
String url = fi.getRequestUrl();
log.info("URL:" + url);
// Will eventually come from database
//List<ConfigAttribute> attributes = SecurityConfig.createList("permitAll");
//List<ConfigAttribute> attributes = SecurityConfig.createList("hasRole('ROLE_ADMIN')");
//List<ConfigAttribute> attributes = SecurityConfig.createList("ROLE_ADMIN");
List<ConfigAttribute> attributes = SecurityConfig.createList("permitAll");
if (!url.equalsIgnoreCase("/login") && !url.contains("/javax.faces.resource/") && !url.contains("/resources/images/"))
return attributes;
else
return null;
}
#Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
#Override
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz);
}
}
and I have a BeanPostProcessor to update the namespace FilterSecurityInterceptor with my custom FilterInvocationSecurityMetadataSource:
#Component
public class MyFilterSecurityInterceptorBeanPostProcessor implements BeanPostProcessor {
#Autowired
CustomFilterInvocationSecurityMetadataSource customFilterInvocationSecurityMetadataSource;
#Override
public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String name) throws BeansException {
if (bean instanceof FilterSecurityInterceptor) {
((FilterSecurityInterceptor) bean).setSecurityMetadataSource(customFilterInvocationSecurityMetadataSource);
}
return bean;
}
}
When I un-comment the antMatchers for /home and /home3 in the configure method and do not use the custom FilterInvocationSecurityMetadataSource and BeanPostProcessor, I can reach /home and /home3 without issue.
The problem I'm having however is that whenever I comment out the antMatchers and attempt to use the custom FilterInvocationSecurityMetadataSource and BeanPostProcessor to provide the access roles, I receive a 403 Forbidden when attempting to reach /home and /home3.
If I return a null from CustomFilterInvocationSecurityMetadataSource it will allow the request to go through successfully, however any request which returns any access role including 'permitAll' returns the 403. Does anyone have any idea why this is happening? Am I missing something? Any help is greatly appreciated!
Thank you!

Related

SecurityContextHolder return wrong user context on concurrent request

I am experiencing a weird problem, When multiple concurrent requests comes to a controllerSecurityContextHolder.getContext().getAuthentication().getPrincipal()
returns same user object sometimes even if the JWT token is different.
#RequestMapping(value = {"/users/{userId}/solveDetail/create"}, method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
#Transactional
public ResponseEntity<CreateSolveDetail> createSolve(#PathVariable("userId") Long userId, #RequestBody CreateSolveDetail createSolveDetail){
User user =SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
So far tried changing session management to .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) and thread strategy is set to SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_THREADLOCAL) still the isssue persists.
Below is the WebSecurityConfig class configured and a custom filter is added which overrides getPreAuthenticatedPrincipal and getPreAuthenticatedPrincipal of AbstractPreAuthenticatedProcessingFilter class.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityBasicConfig {
#Autowired
private Http403ForbiddenEntryPoint http403ForbiddenEntryPoint;
#Bean
public Http403ForbiddenEntryPoint http403ForbiddenEntryPoint() {
return new Http403ForbiddenEntryPoint();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.exceptionHandling()
.authenticationEntryPoint(http403ForbiddenEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(preAuthFilter(), BasicAuthenticationFilter.class);
httpSecurity.csrf().disable();
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_THREADLOCAL);
}
}
public class PreAuthFilter extends AbstractPreAuthenticatedProcessingFilter {
#Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest httpServletRequest) {
String auth = httpServletRequest.getHeader("PRE-AUTH");
try {
User user = new ObjectMapper().readValue(auth, User.class);
return user;
} catch (Exception e) {
return new User();
}
}
#Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest httpServletRequest) {
String auth = httpServletRequest.getHeader("PRE-AUTH");
return auth;
}
}
Please let me know what I am doing wrong here.
Thanks in advance.
Spring boot version : 2.1.6.RELEASE
Architecture: Microservice

Spring Security pre authentication filter gets called every time

I have a Spring Boot app where I have custom pre authentication filter. I want to ignore security for health URL but I am not able to do it. Below is my configuration.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
#Order(1000)
public class UserSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationUserDetailsService<PreAuthenticatedAuthenticationToken> userDetailsService;
#Autowired
private IUserIdentityService iUserIdentityService;
#Value("${spring.profiles.active}")
private String profileType;
#Autowired
#Qualifier("publicEndpoints")
private Map<String, String> publicEndpoints;
#Autowired
private GenericDataService genericDataService;
#Bean(name = "preAuthProvider")
PreAuthenticatedAuthenticationProvider preauthAuthProvider() {
PreAuthenticatedAuthenticationProvider provider = new PreAuthenticatedAuthenticationProvider();
provider.setPreAuthenticatedUserDetailsService(userDetailsService);
return provider;
}
#Bean
AppPreAuthenticatedProcessingFilter appPreAuthenticatedProcessingFilter() throws Exception {
appPreAuthenticatedProcessingFilter filter = new appPreAuthenticatedProcessingFilter(iUserIdentityService, genericDataService);
filter.setAuthenticationManager(super.authenticationManagerBean());
filter.setContinueFilterChainOnUnsuccessfulAuthentication(false);
filter.setCheckForPrincipalChanges(true);
return filter;
}
/**
* Uses JEE pre-authentication filter, that assumes that the user has been
* pre-authenticated into the container.
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/health/e2e").permitAll()
.and()
.addFilter(appPreAuthenticatedProcessingFilter())
.authorizeRequests()
.anyRequest().authenticated()
.and()
.authenticationProvider(preauthAuthProvider())
.csrf()
.csrfTokenRepository(this.csrfTokenRepository())
.and()
.httpBasic().disable();
// Disabling the CSRF implementation, if "csrf.disabled" property set to "true"
// in System Properties.
if (!StringUtils.isEmpty(profileType) && profileType.equals("local")) {
http.csrf().disable();
}
}
/**
* Method to ignore web security for urls
*/
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("*/api-docs", "/configuration/ui", "/swagger-resources/**", "/configuration/**", "/swagger-ui.html", "/webjars/**", "/health/e2e", "*/health/e2e", "**/health/e2e");
}
/**
* Method to to return CsrfTokenRepository
*/
private CsrfTokenRepository csrfTokenRepository() {
CookieCsrfTokenRepository tokenRepository = CookieCsrfTokenRepository.withHttpOnlyFalse();
tokenRepository.setCookiePath("/");
return tokenRepository;
}
}
Custom authentication filter looks like
#Slf4j
public class AppPreAuthenticatedProcessingFilter extends AbstractPreAuthenticatedProcessingFilter {
private IUserIdentityService iUserIdentityService;
private GenericDataService genericDataService;
public AppPreAuthenticatedProcessingFilter(IUserIdentityService iUserIdentityService, GenericDataService genericDataService) {
this.iUserIdentityService = iUserIdentityService;
this.genericDataService = genericDataService;
}
#Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));
return iUserIdentityService.getUserName();
}
#Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest request) {
return AppConst.DEFAULT_CREDENTIAL;
}
}
I am not sure why /health/e2e is secured?
P.S. I tried removing #Bean from pre auth filter but in that case, filter never gets called for any request.
The problem is two fold
Your security setup contains an error
The filter is added to the regular filter bean as well.
With your current security setup the AppPreAuthenticatedProcessingFilter is added only to the /health/e2d URL. Your attempt to fix something has actually broken things instead.
Your configuration should be something along the lines of
http.authorizeRequests().anyRequest().authenticated()
.and().httpBasic()
.and().authenticationProvider(preauthAuthProvider())
.csrf().csrfTokenRepository(this.csrfTokenRepository())
.and().addFilterBefore(appPreAuthenticatedProcessingFilter(), UsernamePasswordAuthenticationFilter.class);
// in System Properties.
if (!StringUtils.isEmpty(profileType) && profileType.equals("local")) {
http.csrf().disable();
}
Spring Boot will by default register an javax.servlet.Filter in the normal filter chain, to disable this you need to add a FilterRegistrationBean to disable this.
#Bean
public FilterRegistrationBean<AppPreAuthenticatedProcessingFilter> preAuthenticationFilterRegistrationBean(AppPreAuthenticatedProcessingFilter filter) {
FilterRegistrationBean<AppPreAuthenticatedProcessingFilter> frb = new FilterRegistrationBean<>(filter);
frb.setEnabled(false);
return frb;
}

Implement Spring Security for Rest Api

I use this code for Rest API authentication:
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
Optional<String> basicToken = Optional.ofNullable(request.getHeader(HttpHeaders.AUTHORIZATION))
.filter(v -> v.startsWith("Basic"))
.map(v -> v.split("\\s+")).filter(a -> a.length == 2).map(a -> a[1]);
if (!basicToken.isPresent()) {
return sendAuthError(response);
}
byte[] bytes = Base64Utils.decodeFromString(basicToken.get());
String namePassword = new String(bytes, StandardCharsets.UTF_8);
int i = namePassword.indexOf(':');
if (i < 0) {
return sendAuthError(response);
}
String name = namePassword.substring(0, i);
String password = namePassword.substring(i + 1);
// Optional<String> clientId = authenticationService.authenticate(name, password, request.getRemoteAddr());
Merchants merchant = authenticationService.authenticateMerchant(name, password, request.getRemoteAddr());
if (merchant == null) {
return sendAuthError(response);
}
request.setAttribute(CURRENT_CLIENT_ID_ATTRIBUTE, merchant.getId());
return true;
}
How I can rewrite the code with Spring Security in order to get the same result but for different links to have authentication? For example:
localhost:8080/v1/notification - requests should NOT be authenticated.
localhost:8080/v1/request - requests should be authenticated.
Here you can find a working project https://github.com/angeloimm/springbasicauth
I know in the pom.xml file there are a lot of useless dependencies but I started from an already existing project and I had no time to depure it
Basically you must:
configure spring security
configure spring mvc
implements your own authentication provider according to spring security. Note I used an inMemoryAuthentication. Please modify it according to yuor own wishes
Let me explain the code.
Spring MVC Configuration:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages= {"it.olegna.test.basic"})
public class WebMvcConfig implements WebMvcConfigurer {
#Override
public void configureMessageConverters(final List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter());
}
}
Here we don't do anything else that configuring spring MVC by telling it where to find controllers and so on and to use a single message converter; the MappingJackson2HttpMessageConverter in order to produce JSON responses
Spring Security Configuration:
#Configuration
#EnableWebSecurity
#Import(value= {WebMvcConfig.class})
public class WebSecConfig extends WebSecurityConfigurerAdapter {
#Autowired private RestAuthEntryPoint authenticationEntryPoint;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("test")
.password(passwordEncoder().encode("testpwd"))
.authorities("ROLE_USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/securityNone")
.permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint);
}
#Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
Here we configure Spring Security in order to use HTTP Basic Authentication for all requests except the ones starting with securityNone. We use a NoOpPasswordEncoder in order to encode the provided password; this PasswrodEncoder does absolutly nothing... it leaves the passwrod as it is.
RestEntryPoint:
#Component
public class RestAuthEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
This entrypoint disables all requests not containg the Authentication header
SimpleDto: a very simple DTO representing the JSON answer form a controller
public class SimpleDto implements Serializable {
private static final long serialVersionUID = 1616554176392794288L;
private String simpleDtoName;
public SimpleDto() {
super();
}
public SimpleDto(String simpleDtoName) {
super();
this.simpleDtoName = simpleDtoName;
}
public String getSimpleDtoName() {
return simpleDtoName;
}
public void setSimpleDtoName(String simpleDtoName) {
this.simpleDtoName = simpleDtoName;
}
}
TestBasicController: a very simple controller
#RestController
#RequestMapping(value= {"/rest"})
public class TestBasicController {
#RequestMapping(value= {"/simple"}, method= {RequestMethod.GET}, produces= {MediaType.APPLICATION_JSON_UTF8_VALUE})
public ResponseEntity<List<SimpleDto>> getSimpleAnswer()
{
List<SimpleDto> payload = new ArrayList<>();
for(int i= 0; i < 5; i++)
{
payload.add(new SimpleDto(UUID.randomUUID().toString()));
}
return ResponseEntity.ok().body(payload);
}
}
So if you try this project by using postman or any other tester you can have 2 scenarios:
authentication required
all ok
Let's suppose you want to invoke the URL http://localhost:8080/test_basic/rest/simple without passing the Authentication header. The HTTP Status code will be 401 Unauthorized
This means that the Authentication Header is required
By adding this header to the request Authorization Basic dGVzdDp0ZXN0cHdk all works pretty good
Note that the String dGVzdDp0ZXN0cHdk is the Base64 encoding of the string username:password; in our case is the Base64 encoding of test:testpwd defined in the inMemoryAuthentication
I hope this is usefull
Angelo
WEB SECURITY USER DATAIL SERVICE
In order to configure Spring security to retrieve user details from DB you must do the following:
create a org.springframework.security.core.userdetails.UserDetailsService implementation like this:
#Service
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private BasicService svc;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
BasicUser result = svc.findByUsername(username);
if( result == null )
{
throw new UsernameNotFoundException("No user found with username "+username);
}
return result;
}
}
Inject it to the spring security configuration and use it like this:
public class WebSecConfig extends WebSecurityConfigurerAdapter {
#Autowired private RestAuthEntryPoint authenticationEntryPoint;
#Autowired
UserDetailsService userDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// auth
// .inMemoryAuthentication()
// .withUser("test")
// .password(passwordEncoder().encode("testpwd"))
// .authorities("ROLE_USER");
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider());
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/securityNone")
.permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint);
}
#Bean
public PasswordEncoder passwordEncoder() {
return NoOpPasswordEncoder.getInstance();
}
}
I pushed the code on the github link I provided. There you can find a full working example based on:
spring 5
spring security 5
hibernate
h2 DB
Feel free to adapt it to your own scenario
You can use a default spring-security configuration described on various websites, like baeldung.com or mkyong.com. The trick in your sample seems to be the call to get the Merchant. Depending on the complexity of the authenticationService and the Merchant object, you can either use the following code, or implement a facade to get similar behaviour.
#Autowired
public void authenticationManager(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(new AuthenticationProvider() {
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Merchants merchant = authenticationService.authenticateMerchant(name, password, request.getRemoteAddr());
if(merchant == null) {
throw new AuthenticationException("No Merchant found.");
}
return new UsernamePasswordAuthenticationToken(name, password, merchant.getAuthorities());
}
#Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
});
}
Setting the attribute on the request, if necessary could be done by a separate filter which takes the Principal from the SecurityContext and puts it on the request as an attribute.

Not able to recognize user ROLE when redirecting page using Spring Security

I am working on my project with Spring security and Thymeleaf. I have basic Spring Security integration.
SecurityConfig.java
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
private DataSource dataSource;
#Autowired
public void configureGlobal (AuthenticationManagerBuilder auth) throws Exception
{
auth
.jdbcAuthentication()
.dataSource(dataSource);
}
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/success", true)
.and()
.httpBasic();
}
}
SecurityWebApplicationInitializer.java
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer
{
public SecurityWebApplicationInitializer(){
super(SecurityConfig.class);
}
}
Controller.java
#Controller
public class HomeController {
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String loginPage(Model model) {
return "login";
}
#RequestMapping("/success")
public String loginPageRedirect(HttpServletRequest httpServletRequest){
if(httpServletRequest.isUserInRole("ROLE_ADMIN")) {
return "index1";
} else if(httpServletRequest.isUserInRole("ROLE_USER")) {
return "index2";
} else {
return "index3";
}
}
}
When I have successful login my user is redirected, but to wrong page. My user has role ROLE_USER but method loginPageRedirect is redirecting him to page index3 when it should be index2. I guess my user role is not recognize. How can I do that? Should I add something as parameter to loginPageRedirect so it recognizes role?
I found solution that works for me.
I edited my loginPageRedirect method like this:
#RequestMapping("/success")
public void loginPageRedirect(HttpServletRequest request, HttpServletResponse response, Authentication authResult) throws IOException, ServletException {
String role = authResult.getAuthorities().toString();
if(role.contains("ROLE_ADMIN")){
response.sendRedirect(response.encodeRedirectURL(request.getContextPath() + "/index1"));
}
else if(role.contains("ROLE_USER")) {
response.sendRedirect(response.encodeRedirectURL(request.getContextPath() + "/index2"));
}
}
Hope it helps someone with same issue :)

Spring boot OAuth successful login listener not triggering

Using Spring boot - After successfully authenticating with GitHub OAuth, the Audit listener is not being triggered.
public class AuthenticationListener implements ApplicationListener<InteractiveAuthenticationSuccessEvent> {
#Override
public void onApplicationEvent(final InteractiveAuthenticationSuccessEvent event) {
System.out.println("+++++++ ================ ------------");
}
}
Do I need to register it anywhere else? I have tried as suggested else where on Stackoverflow to create a #Bean, but this made no difference.
Full code https://github.com/DashboardHub/PipelineDashboard/tree/feature/178-login-github
Update
SecurityConfig class
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
OAuth2ClientContext oauth2ClientContext;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/", "/login**", "/webjars/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")//.failureUrl("/login?error")
.permitAll()
.and().logout().logoutSuccessUrl("/").permitAll()
.and().addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class)
;
}
#Bean
#ConfigurationProperties("security.oauth2")
ClientResourcesConfig github() {
return new ClientResourcesConfig();
}
private Filter ssoFilter() {
CompositeFilter filter = new CompositeFilter();
List<Filter> filters = new ArrayList<>();
filters.add(ssoFilter(this.github(), "/login/github"));
filter.setFilters(filters);
return filter;
}
private Filter ssoFilter(ClientResourcesConfig client, String path) {
OAuth2ClientAuthenticationProcessingFilter githubFilter = new OAuth2ClientAuthenticationProcessingFilter(
path);
OAuth2RestTemplate githubTemplate = new OAuth2RestTemplate(client.getClient(),
oauth2ClientContext);
githubFilter.setRestTemplate(githubTemplate);
githubFilter.setTokenServices(new UserInfoTokenServices(
client.getResource().getUserInfoUri(), client.getClient().getClientId()));
return githubFilter;
}
}
I got this working by injecting the default ApplicationEventPublisher into your security config bean. Then setting this as the application event publisher on the processingfilter:
#Autowired
private ApplicationEventPublisher applicationEventPublisher;
...
githubFilter.setApplicationEventPublisher(applicationEventPublisher);
For some reason, the application event publisher on the filter is a NullEventPublisher by default.
Use #Configuration annotation on AuthenticationListener class to register it in your application context.
EDIT
As I could not figure out why event wasn't fired, I present alternative solution for this problem. You have to create class that implements AuthenticationSuccessHanddler and implement its onAuthenticationSuccess method:
#Component(value="customAuthenticationSuccessHandler")
public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler{
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
//implementation
}
}
Then add it to your configuration like:
#Resource
private CustomAuthenticationSuccessHandler customAuthenticationSuccessHandler;
#Override
protected void configure(HttpSecurity http) throws Exception {
...
.loginPage("/login").and()
.successHandler(getCustomAuthenticationSuccessHandler())
.permitAll()
...
}
public CustomAuthenticationSuccessHandler getCustomAuthenticationSuccessHandler() {
return customAuthenticationSuccessHandler;
}
It's not exactly what you wanted, but should solve your problem.
Instead of an InteractiveAuthenticationSuccessEvent, listening for an AuthenticationSuccessEvent did the trick for me.
However, the listener is called twice: first one's event's Authentication is an UsernamePasswordAuthenticationToken, while the second one is an OAuth2Authentication

Resources