I have a Spring MVC controller where I save the post information associated with the currently authenticated user. This current user is obtained by using the @AuthenticationPrincipal annotation in the method next to the User class that implements the UserDetails interface. The problem is that this user has all the empty fields, however if I get the user through SecurityContextHolder this does not happen.
When the controller is executed the user obtained by @AuthenticationPrincipal is empty and the one obtained by SecurityContextHoldercontains all the information:
2016-12-10 19:37:52 INFO PostController:62 - Informaci贸n del usuario mediate @CurrentUser: User{id=null, username=null, passwordClear=null, confirmPassword=null, password=null, email=null, enabled=true, fullName=null, posts=[]}
2016-12-10 19:37:52 INFO PostController:63 - Informaci贸n del usuario mediate SecurityContextHolder: User{id=1, username=sergio11, passwordClear=null, confirmPassword=null, password=$2a$10$LJvYTNacIvqZWDQWjF7xaeheK1MrF.FkXxovb2QgcF2CMudA1mM/., [email protected], enabled=true, fullName=Sergio S脙隆nchez S脙隆nchez, posts=[]}
As I understand using @EnableWebSecurity already enable in the context the resolver argument for the @AuthenticationPrincipal.
So I could use this to get the current user managed:
@AuthenticationPrincipal(expression = "@jpaEntityManager.merge(#this)")
And to be able to persist the Post associated with the current user
package config.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import services.security.CustomUserDetailsService;
/**
*
* @author sergio
*/
@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = CustomUserDetailsService.class)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
private DefaultAuthenticationEventPublisher defaultAuthenticationEventPublisher;
@Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.authenticationEventPublisher(defaultAuthenticationEventPublisher)
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/signup").anonymous()
.antMatchers("/admin/**").authenticated()
.anyRequest().permitAll()
.and()
.formLogin().loginPage("/admin/login").permitAll()
.usernameParameter("username").passwordParameter("password")
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/admin/logout"))
.logoutSuccessUrl("/admin/login?logout")
.and()
.exceptionHandling().accessDeniedPage("/403")
.and()
.csrf();
}
@Bean
public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
return new DefaultAuthenticationEventPublisher(applicationEventPublisher);
}
}
package config;
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
/**
*
* @author sergio
*/
public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
}
Spring Security 4.2.0.RELEASE
This issue is because DelegatingFlashMessagesConfiguration eagerly initializes the handlerExceptionResolver which prevents the AuthenticationPrincipalArgumentResolver from being registered until after Spring MVC has constructed the DispatcherServlets custom argument resolvers.
# Details
DelegatingWebMvcConfiguration the container finds all the WebMvcConfigurer. Then DelegatingFlashMessagesConfiguration is created but it requires the handlerExceptionResolver which adds all the argument resolvers before WebMvcSecurityConfiguration is added as a WebMvcConfigurer.
If you comment out the @EnableFlashMessages it resolves this problem.