user25131521
user25131521

Reputation: 1

Spring Boot Vaadin Login Issue: Unable to Authenticate User

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

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

  1. User Registration and Password Encoding:

    • Verified that users are being registered correctly, and passwords are being encoded using BCryptPasswordEncoder. Expected the login to work with the registered user credentials.
  2. Security Configuration:

    • Configured UserDetailsService in SecurityConfig to use UserService. Expected the loadUserByUsername method to be called during the login attempt.
  3. Login Form Configuration:

    • Set the login form action URL to match the one expected by Spring Security. Expected the login to succeed with correct credentials.
  4. Debug Logging:

    • Added debug logs to verify that the loadUserByUsername method is being called and returning the correct user details. Expected the logs to show successful login attempts.

Upvotes: 0

Views: 178

Answers (1)

Debid
Debid

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

Related Questions