I am trying to migrate a code that used the old springboot security configuration with the WebSecurityConfigurerAdapter to the new component based security config, i have a custom authentication filter that extends UsernamePasswordAuthenticationFilter that want to include in my SecurityFilterChain bean as is showed here:
SecurityConfig.java file
package com.tito.userservice.security;
import com.tito.userservice.filter.CustomAuthenticationFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
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.SecurityFilterChain;
@Configuration @EnableWebSecurity @RequiredArgsConstructor
public class SecurityConfiguration {
private final UserDetailsService userDetailsService;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
@Bean
public PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
//----------------HTTP SECURITY CONFIG-------------------------------------
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http
.authorizeRequests().anyRequest().permitAll();
http.addFilter(new CustomAuthenticationFilter(authenticationManager()));
return http.build();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration)
throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
//----------------HTTP SECURITY CONFIG-------------------------------------
}
for that I created a Bean of type AuthenticationManager and tryed to use it in my CustomAuthenticationFilter but i got the following error:
the code of my CustomAuthenticationFilter is :
CustomAuthenticationFilter.java file
package com.tito.userservice.filter;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.tito.userservice.domain.AppUser;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.core.userdetails.User;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.Date;
import java.util.stream.Collectors;
@Slf4j
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final AuthenticationManager authenticationManager;
public CustomAuthenticationFilter(AuthenticationManager authenticationManager){
this.authenticationManager = authenticationManager;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
String username = request.getParameter("username");
String password = request.getParameter("password");
log.info("Username is: {}", username); log.info("Password is: {}",password);
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username,password);
return authenticationManager.authenticate(authenticationToken);
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authentication) throws IOException, ServletException {
User user = (User)authentication.getPrincipal();
Algorithm algorithm = Algorithm.HMAC256("secret".getBytes());
String access_token = JWT.create()
.withSubject(user.getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() 10*60*1000))
.withIssuer(request.getRequestURL().toString())
.withClaim("roles",user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
.sign(algorithm);
String refresh_token = JWT.create()
.withSubject(user.getUsername())
.withExpiresAt(new Date(System.currentTimeMillis() 30*60*1000))
.withIssuer(request.getRequestURL().toString())
.sign(algorithm);
response.setHeader("acces_token",access_token);
response.setHeader("refres_token",refresh_token);
}
}
there you can see that the constructor expects a AuthenticationManager argument so thats why i pass the created bean as the argument, how can i fix this, is there something i am missing? also the stack trace when running the app is:
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] /C:/Users/user/workspace/spring-security/userservice/src/main/java/com/tito/userservice/security/SecurityConfiguration.java:[47,55] method authenticationManager in class com.tito.userservice.security.SecurityConfiguration cannot be applied to given types;
required: org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration
found: no arguments
reason: actual and formal argument lists differ in length
[INFO] 1 error
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.968 s
[INFO] Finished at: 2022-08-16T13:01:40-05:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.10.1:compile (default-compile) on project userservice: Compilation failure
[ERROR] /C:/Users/user/workspace/spring-security/userservice/src/main/java/com/tito/userservice/security/SecurityConfiguration.java:[47,55] method authenticationManager in class com.tito.userservice.security.SecurityConfiguration cannot be applied to given types;
[ERROR] required: org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration
[ERROR] found: no arguments
[ERROR] reason: actual and formal argument lists differ in length
[ERROR]
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
CodePudding user response:
You can inject a bean of type AuthenticationManagerBuilder
into your SecurityConfiguration
and utilize its getOrBuild()
method, which doesn't raise exceptions, to get an instance of AuthenticationManager
.
So, your SecurityConfiguration
might look like this:
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfiguration {
private final UserDetailsService userDetailsService;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
private final AuthenticationManagerBuilder authManagerBuilder;
// some beans
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests().anyRequest().permitAll()
.and()
.addFilter(new CustomAuthenticationFilter(authManagerBuilder.getOrBuild()));
return http.build();
}
}