1

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.

Genesis
  • 13
  • 6
Genesis
  • 55
  • 3
  • 13

2 Answers2

4

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.

Leffchik
  • 1,950
  • 14
  • 16
  • Hello thank you for your answer! I will update my code and post it. I added a method to encrypt the password but how do I save it again in application.properties? – Genesis Mar 21 '18 at 14:04
  • @Genesis, wait, why are you trying to hash your password in your updated code? Maybe I missunderstood your question.. You want to store hashed password in your properies file, right? – Leffchik Mar 21 '18 at 14:19
  • but iam still getting that error whenever I try to run app – Genesis Mar 21 '18 at 14:23
  • @Genesis, looks like you are using wrong import (wrong package). Please, use `org.springframework.security.crypto.password.PasswordEncoder`. – Leffchik Mar 21 '18 at 14:24
  • @Genesis, as for saving hashed password into application properties... Well, thats good question :) You can write very simple java app to encrypt your passwords - [like this one](https://stackoverflow.com/a/34210582/2653420). Then you can put the result into your application.properties. This might be a bit hacky, but thats what I would do :) – Leffchik Mar 21 '18 at 14:27
  • iam using the right import, I updated my post with imports – Genesis Mar 21 '18 at 14:28
  • I updated my post wiht some thoughts, check it out please – Genesis Mar 21 '18 at 22:05
  • @Genesis, I'm not sure I understand what is the problem. Did you put your hashed passoword into application.properties file? And it works? So, what is the problem? Isn't it what you wanted in a first place? :) – Leffchik Mar 22 '18 at 05:35
  • How can I get the password parameter from the login popup that appears when entering localhost so that I can compare that password with the generated hash – Genesis Mar 22 '18 at 10:19
  • @Genesis, considering your current configuration with inmemory auth and password encoder provided for it - spring does this things for you. If you want to do it manually for some reason, you'll have to implement your custom `AuthenticationProvider`. – Leffchik Mar 22 '18 at 10:58
  • But I get the same error whenever I try to use that line: "Error:(38, 38) java: cannot access org.springframework.security.authentication.encoding.PasswordEncoder class file for org.springframework.security.authentication.encoding.PasswordEncoder not found" – Genesis Mar 22 '18 at 11:21
  • Nvm I got it to work, had to remove a spring security dependency that was in conflict with another spring security – Genesis Mar 22 '18 at 11:30
  • @Genesis, so, is everything OK now? :) – Leffchik Mar 22 '18 at 11:31
  • @Genesis, sorry, but I dont understand what r u trying to achieve. The way it works right now: user enters login/password into popup, spring gets them, hashes entered password and compares it to the hashes password from application.properties. If there is a match - logging user in. This is not what you wanted? – Leffchik Mar 22 '18 at 11:39
  • It works as intended now! sorry for the misconfusion! everything works fine now! Thank you for your time and help my friend – Genesis Mar 22 '18 at 11:45
0

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.

markusw
  • 1,975
  • 16
  • 28