I am rebuilding an old Spring Boot application which was using old version of spring-boot and spring-security with java 8. I am currently using 3.3.2 for spring-boot and 6.3.1 for spring-security.
The ‘login’ worked the following way in the old application:
There were different configurations for the deployed and the local version.
The local version was using a custom form login, where the only field used for authentication was ‘username’ and the username was stored in the database with an ‘is_admin’ flag. If the user id entered was not found, then it was saved in the database, what basically means that every username is allowed and saved, but not all are admins.
The deployed version used oauth2 and the user id was taken from the properties and saved if not found in the database.
I am trying to implement the local authentication with the current versions but I am not able to get it working. I need to have a custom UsernamePasswordAuthenticationFilter implementation to set roles based on the username. I have created a filter which is called and is setting the authorities for the given user and generates a UsernamePasswordAuthenticationToken.
I am doing it the following way but the SecurityContext does not have the UsernamePasswordAuthenticationToken.
public class LocalAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
public LocalAuthenticationFilter(UserService userService) {
super();
setAuthenticationManager(new LocalAuthenticationManager(userService));
}
public static class LocalAuthenticationManager implements AuthenticationManager {
private final UserService userService;
public LocalAuthenticationManager(UserService personService) {
this.userService = personService;
}
@Override
public Authentication authenticate(Authentication authentication) {
String username = authentication.getName();
if (!StringUtils.hasText(username)) {
throw new BadCredentialsException("Username is empty");
}
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
mappedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
User user = userService.findByUid(username); // This method saves the username if not found
if (user.isAdmin()) {
mappedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
}
return new UsernamePasswordAuthenticationToken(username, "", mappedAuthorities);
}
}
}
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private static final String[] AUTH_ALLOWED = {
// some allowed endpoints
};
private final UserService userService;
@Autowired
public SecurityConfig(
UserService userService) {
this.userService = userService;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(
(authorize) ->
authorize.requestMatchers(AUTH_ALLOWED).permitAll().anyRequest().authenticated())
.addFilterBefore(
new LocalAuthenticationFilter(userService), UsernamePasswordAuthenticationFilter.class)
.formLogin(form -> form.loginPage("/").permitAll())
.logout(LogoutConfigurer::permitAll);
return http.build();
}
}
@Controller
@RequestMapping("/")
public class MainController {
@GetMapping
public String index(Authentication authentication) {
SecurityContext securityContext = SecurityContextHolder.getContext();
if (authentication == null || securityContext.getAuthentication() instanceof AnonymousAuthenticationToken) {
return "login";
}
return "index";
}
}
What am I doing wrong? How should I be setting the UsernamePasswordAuthenticationToken?
4