Genesis
Genesis

Reputation: 55

Java - Spring - Basic authentication - How to hash the password defined in application.properties

Iam implementing a basic authentication for Spring Boot application and iam defining my credentials in application.properties class but I want to hash-encode the password and then check if the hash is the same as the hash for the password in application.properties then I can login. If possible to do all of the logic in the configure method then it would be great.

application.properties:

BASIC AUTHENTICATION

user.name=test
user.password={noop}example

SecurityConfig class:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);

    private AuthenticationProvider authenticationProvider;

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

        http.csrf().disable().authorizeRequests().anyRequest().authenticated().and().httpBasic()
                .and().sessionManagement().and().authenticationProvider(authenticationProvider)
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    }

UPDATED CODE

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);

    @Value("${security.user.password}")
    private String password;
    @Value("${security.user.name}")
    private String username;

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

        http.csrf().disable().authorizeRequests().anyRequest().authenticated()
                .and().logout().and().httpBasic().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);


    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().
                passwordEncoder(passwordEncoder()).withUser(username).password(password);
    }

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

    @Bean
    public String generateHashedPassword(String password) {
        return BCrypt.hashpw(password, BCrypt.gensalt(10));
    }
}

UPDATE 2

Currently the way it works now is when i start the application, i visit localhost:8080 then a login popup appears and i type the username and password (that are defined in application.properties)

if I type the right username and password i get logged in but if i manage to login with the username and password defined in application.properties then whats the point with hashing the password? I was thinking more like having a list of hashed keys and compare the input password with the list and if success then login.

Upvotes: 1

Views: 6777

Answers (2)

Leffchik
Leffchik

Reputation: 2030

Since you want to define your credentials in properties file, I guess you can take advantage of inmemory authentication. Try the following:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);

    private AuthenticationProvider authenticationProvider;

    @Value("${user.name}") 
    private String userName;

    @Value("${user.password}") 
    private String userHashedPassword; // hashed password

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

    http.csrf().disable().authorizeRequests().anyRequest().authenticated().and().httpBasic()
            .and().sessionManagement().and().authenticationProvider(authenticationProvider)
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception
    {
        auth
           .inMemoryAuthentication()
           .passwordEncoder(passwordEncoder())
           .withUser(userName)
           .password(userHashedPassword);
    }

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

Please, note, that in this case your password should be encrypted with BCryptPasswordEncoder first, and then you should put it into properties file (you can use its encoder.encode("password") method). Or you can use any other implementation of PasswordEncoder if you want. I've also noticed that you're using some custom autenticationProvider. Not sure how it works since you didnt share the code, and not sure that it will get along with inmemory autentication. But, anyway, I think it worth a shot and this is the right way to go in your scenario. Hope it helps.

Upvotes: 4

markusw
markusw

Reputation: 2055

I think you need to implement your own AuthenticationProvider like in this question. In the authenticate() method you can do the hashing of the retrieved password and check if it matches the one from your application.properties.

Upvotes: 0

Related Questions