Search code examples
androidspring-securityretrofitretrofit2bcrypt

Getting different encoded password after using PasswordEncoder in Spring security


I'm trying to perform an authentication from an android app. I'm basically sending the username and password(not encoded) to my rest api endpoint which is : /api/management/login I'm using Retrofit). After that, I check if the user exists or not and return the object if it does or null if it does not.I noticed that the encoded password is different from the one stored in my database even if the initial password strings are the same. I read that PasswordEncoder interface is generating a random salt in order to encode the password. Is there a way to make salt unique ? Here is my spring security configuration file :


@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    private UserPrincipalDetailsService userPrincipalDetailsService;

    public SecurityConfiguration(UserPrincipalDetailsService userPrincipalDetailsService) {
        this.userPrincipalDetailsService = userPrincipalDetailsService;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(authenticationProvider());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {


            http.csrf()
            .disable()
            .exceptionHandling()
            .authenticationEntryPoint(new Http403ForbiddenEntryPoint() {}).and()
            .authenticationProvider(authenticationProvider())
            .authorizeRequests()
                .antMatchers("/management/*").hasRole("ADMIN")
                .antMatchers("/*").hasRole("ADMIN")
                .antMatchers("/management/professor*").hasRole("ADMIN")
                .antMatchers("/management/absence*").hasRole("ADMIN")
                .antMatchers("/management/room*").hasRole("ADMIN")
                .anyRequest().permitAll()
                .and()
                .formLogin()
                .loginProcessingUrl("/signin").permitAll()
                .loginPage("/login").permitAll()
                .successHandler(mySimpleUrlAuthenticationHandler())
                .failureUrl("/login?error=true")
                .usernameParameter("username")
                .passwordParameter("password")
                .and()
                .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/login")
                .and()
                .rememberMe().userDetailsService(userPrincipalDetailsService).rememberMeParameter("checkRememberMe");
    }

    @Bean
    DaoAuthenticationProvider authenticationProvider(){
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
        daoAuthenticationProvider.setUserDetailsService(this.userPrincipalDetailsService);

        return daoAuthenticationProvider;
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    MySimpleUrlAuthenticationHandler mySimpleUrlAuthenticationHandler() {
        return new MySimpleUrlAuthenticationHandler();
    }
}

any recommendations ?


Solution

  • I think you're encoding the password that you received from the client and hard-coding that into SQL query with login id. If my assumption is correct, don't do that.

    As you said

    I check if the user exists or not and return the object if it does or null if it does not

    Do not encode password and concatenate it to SQL query (in /login API). Instead, retrieve the data only based on login id. If it returns an object, then obviously it returns an encoded password. Now you need to compare already enoded passwords with the plain password received from the client.

    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    
    BCryptPasswordEncoder encoded = BCryptPasswordEncoder();
    boolean matches = encoder.matches("plain password from client", "encoded password here");
    
    if (matches) {
       // successull login
    } else {
       // invalid login credentials
    }
    

    For more refer to this BCryptPasswordEncoder#matches() SpringBoot doc