Reputation: 1
Problem Description
I am developing a Spring Boot application with Vaadin for the frontend, and I am encountering an issue where users are unable to log in. Despite registering users and saving them to the database with encrypted passwords, the login attempts always fail, resulting in a "Unable to log in. Check that you have entered your email and password correctly." error message.
Environment
Spring Boot: 3.2.5
Vaadin: 24.3.11
Java: 17
Database: MySQL
Security Configuration
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private static final Logger logger = Logger.getLogger(SecurityConfig.class.getName());
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsService userDetailsService(UserService userService) {
return userService;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
logger.info("Configuring Security Filter Chain");
http
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login", "/register", "/error").permitAll()
.requestMatchers("/api/todos/**").authenticated()
.requestMatchers("/todos/**").authenticated()
.requestMatchers("/api/users/**").authenticated()
.anyRequest().permitAll())
.formLogin(form -> form
.loginPage("/login")
.loginProcessingUrl("/login")
.defaultSuccessUrl("/todos", true)
.failureUrl("/login?error=true")
.permitAll())
.logout(logout -> logout
.logoutUrl("/logout")
.logoutSuccessUrl("/login?logout=true")
.permitAll());
logger.info("Security Filter Chain configured");
return http.build();
}
}
User Service:
@Service
public class UserService implements UserDetailsService {
private static final Logger logger = Logger.getLogger(UserService.class.getName());
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
@Autowired
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
public List<User> findAllUsers() {
return userRepository.findAll();
}
public Optional<User> findUserById(UUID id) {
return userRepository.findById(id);
}
public Optional<User> findUserByEmail(String email) {
return userRepository.findByEmail(email.toLowerCase());
}
public User saveUser(User user) {
logger.info("Saving user with email: " + user.getEmail());
String originalPassword = user.getPassword();
user.setPassword(passwordEncoder.encode(user.getPassword()));
logger.info("Original password: " + originalPassword);
logger.info("Encoded password: " + user.getPassword());
user.setEmail(user.getEmail().toLowerCase());
User savedUser = userRepository.save(user);
logger.info("User saved with ID: " + savedUser.getId());
return savedUser;
}
public void deleteUser(UUID id) {
userRepository.deleteById(id);
}
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
logger.info("Loading user by email: " + email);
User user = userRepository.findByEmail(email.toLowerCase())
.orElseThrow(() -> {
logger.warning("User not found with email: " + email);
return new UsernameNotFoundException("User not found with email: " + email);
});
logger.info("User found: " + user.getEmail() + ", password: " + user.getPassword());
return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(), Collections.emptyList());
}
}
Login View:
@Route("login")
@PageTitle("Login | Todo")
@CssImport("./styles/todo-view.css")
@AnonymousAllowed
public class LoginView extends VerticalLayout implements BeforeEnterObserver {
private static final Logger logger = Logger.getLogger(LoginView.class.getName());
private final LoginForm loginForm = new LoginForm();
public LoginView() {
addClassName("login-view");
setSizeFull();
loginForm.setForgotPasswordButtonVisible(false);
loginForm.setAction("login");
loginForm.setI18n(createLoginI18n());
VerticalLayout loginFormContainer = new VerticalLayout();
loginFormContainer.addClassName("login-form-container");
loginFormContainer.setSizeUndefined();
loginFormContainer.setAlignItems(Alignment.CENTER);
Anchor registerLink = new Anchor("register", "No account yet? Register here.");
registerLink.addClassName("login-link");
loginFormContainer.add(new H1("TodoApp Login"), loginForm, registerLink);
add(loginFormContainer);
}
private LoginI18n createLoginI18n() {
LoginI18n i18n = LoginI18n.createDefault();
i18n.getForm().setUsername("E-mail");
i18n.getForm().setTitle("Log in");
i18n.getForm().setSubmit("Log in");
i18n.getForm().setPassword("Password");
i18n.getErrorMessage().setTitle("Unable to log in");
i18n.getErrorMessage().setMessage("Check that you have entered your email and password correctly.");
return i18n;
}
@Override
public void beforeEnter(BeforeEnterEvent event) {
if (event.getLocation().getQueryParameters().getParameters().containsKey("error")) {
loginForm.setError(true);
logger.warning("Login attempt failed.");
}
}
}
Issue Observed
User registration works, and the user data is saved in the database with an encrypted password.
When attempting to log in with the registered user credentials, the login fails with the message: "Unable to log in. Check that you have entered your email and password correctly."
Debug logs show that the loadUserByUsername method in UserService is not being called during the login attempt.
User Registration and Password Encoding:
Security Configuration:
UserDetailsService
in SecurityConfig
to use UserService
. Expected the loadUserByUsername
method to be called during the login attempt.Login Form Configuration:
Debug Logging:
loadUserByUsername
method is being called and returning the correct user details. Expected the logs to show successful login attempts.Upvotes: 0
Views: 178
Reputation: 1
It seems you did not encrypt the password before loadUserByUsername was called.
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
logger.info("Loading user by email: " + email);
User user = userRepository.findByEmail(email.toLowerCase())
.orElseThrow(() -> {
logger.warning("User not found with email: " + email);
return new UsernameNotFoundException("User not found with email: " + email);
});
logger.info("User found: " + user.getEmail() + ", password: " + user.getPassword());
return new org.springframework.security.core.userdetails.User(user.getEmail(),
passwordEncoder.encode(user.getPassword()), // here
Collections.emptyList());
}
or need to create new bean in securityconfig.
Upvotes: 0