I am getting StackOverflowError while using authenticationManger.authenticate(). I see question already answered here: Why AuthenticationManager is throwing StackOverflowError?, but im not extending deprecated WebSecurityConfigurerAdapter, so my configuration looks like this:
@Configuration
@EnableWebSecurity
public class SecurityConfig{
@Bean
public UserDetailsService userDetailsService() {
return new CustomUserDetailsService();
}
@Bean
@Order(1)
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.httpBasic().disable().csrf().disable().sessionManagement()
.and().authorizeRequests()
.antMatchers("/**").permitAll()
.anyRequest().authenticated().and().csrf().disable();
http
.logout()
.invalidateHttpSession(true)
.logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK));
return http.build();
}
@Bean
@Order(0)
public SecurityFilterChain resources(HttpSecurity http) throws Exception {
http.requestMatchers((matchers) -> matchers.antMatchers("*.bundle.*"))
.authorizeHttpRequests((authorize) -> authorize.anyRequest().permitAll())
.requestCache().disable()
.securityContext().disable()
.sessionManagement().disable();
return http.build();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
@Bean
public PasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
And i still get
2022-07-18 17:26:52.277 ERROR 12368 --- [nio-8080-exec-2] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Handler dispatch failed; nested exception is java.lang.StackOverflowError] with root cause
java.lang.StackOverflowError: null
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.21.jar:5.3.21]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) ~[spring-aop-5.3.21.jar:5.3.21]
at com.sun.proxy.$Proxy111.authenticate(Unknown Source) ~[na:na]
at jdk.internal.reflect.GeneratedMethodAccessor60.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.21.jar:5.3.21]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) ~[spring-aop-5.3.21.jar:5.3.21]
at com.sun.proxy.$Proxy111.authenticate(Unknown Source) ~[na:na]
at jdk.internal.reflect.GeneratedMethodAccessor60.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:344) ~[spring-aop-5.3.21.jar:5.3.21]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) ~[spring-aop-5.3.21.jar:5.3.21]
at com.sun.proxy.$Proxy111.authenticate(Unknown Source) ~[na:na]
at jdk.internal.reflect.GeneratedMethodAccessor60.invoke(Unknown Source) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
*continues till stack overflow*
Current version of AuthenticationManager bean i borrowed here (in comment section): spring.io docs
Im using AuthenticationManager in my controller to manually authentificate users:
@CrossOrigin
@RestController
public class UserController {
@Autowired
AuthenticationManager authenticationManager;
@Autowired
CustomUserService userService;
@Autowired
JwtTokenProvider jwtTokenProvider;
@PostMapping("/login")
public ResponseEntity<Map<Object, Object>> login(@RequestBody CustomUserLoginDto userDto) {
try {
String email = userDto.getEmail();
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(email, userDto.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String token = jwtTokenProvider.createToken(email);
Map<Object, Object> model = new HashMap<>();
model.put("username", email);
model.put("token", token);
return ResponseEntity.ok(model);
} catch (AuthenticationException e) {
throw new BadCredentialsException("Invalid email/password supplied");
}
}
@PostMapping("/register")
public CustomUser register(@RequestBody CustomUserCreateDto userDto) {
return userService.saveUser(userDto);
}
}
How can i solve this?
It's better to replace your login method with a custom filter which is extending AbstractAuthenticationProcessingFilter
public class AuthenticationFilter extends AbstractAuthenticationProcessingFilter {
protected AuthenticationFilter() {
super("/login");
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (!request.getMethod().equalsIgnoreCase(HttpMethod.POST.name())) {
return null;
}
// extract login and password
return getAuthenticationManager().authenticate(new UsernamePasswordAuthenticationToken(login, password));
}
}
To access AuthenticationManager you should use custom DSL (Accessing the local AuthenticationManager)
public class CustomDsl extends AbstractHttpConfigurer<CustomDsl, HttpSecurity> {
@Override
public void configure(HttpSecurity http) throws Exception {
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
http.addFilterAfter(authenticationFilter(authenticationManager), ConcurrentSessionFilter.class);
}
public AuthenticationFilter authenticationFilter(AuthenticationManager authenticationManager) {
final AuthenticationFilter authenticationFilter = new AuthenticationFilter();
authenticationFilter.setAuthenticationManager(authenticationManager);
authenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler());
authenticationFilter.setAuthenticationFailureHandler(authenticationFailureHandler());
return authenticationFilter;
}
public AuthenticationSuccessHandler authenticationSuccessHandler() {
return new CustomAuthenticationSuccessHandler();
}
public AuthenticationFailureHandler authenticationFailureHandler() {
return new CustomAuthenticationFailureHandler();
}
}
then apply it
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// ...
http.apply(customDsl());
return http.build();
}
and remove this from your config
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With