0

I have password which is hashed in database while saving it. But I am now implementing login module and not able to compare two passwords in spring [boot] data jpa. This is trying comparing text password that I enter to the password that is hashed in database which obviously fails.

I know this has been answered here using java for general case but not for spring boot.

I somehow need to manipulate logic in this code

@Override
public boolean getLoggedinUser(User user) {

    String uname = user.getUsername();
    String email = user.getEmail();
    String password = user.getPassword();

    System.out.println("sanity check username----- " + uname  + 
            " password ------- " + password);

    if ((userRepo.findByUsername(uname) != null && userRepo.findByPassword(password) != null)
            || (userRepo.findByPassword(password) != null && userRepo.findByEmail(email) != null)) {

        return true;
    }
    else return false;
}

Now, how to compare them ? Any solution is appreciated.

Badri Paudel
  • 1,365
  • 18
  • 19
  • The only solution i see is to move the hashing/encoding mechanism out of the db and apply it to the given password. This way you can compare both hashed/encoding passwords. – Benjamin Eckardt Jun 02 '20 at 15:12
  • Have you considered using BCrypt? https://stackoverflow.com/questions/26905721/decode-the-bcrypt-encoded-password-in-spring-security-to-deactivate-user-account – Romano Jun 02 '20 at 15:17
  • @Romano yes Im using Bcrypt . BCryptPasswordEncoder bcryptEncoder = new BCryptPasswordEncoder(); boolean isMatched = bcryptEncoder.matches(password, userRepo.findByPassword(password)); System.out.println("matched ???? ----------------" + isMatched); returns false why ? I have entered password correctly. – Badri Paudel Jun 02 '20 at 15:34
  • Are you 100% sure the DB password have been generated using BCrypt as well? If yes, are you using salts? – Romano Jun 02 '20 at 19:09
  • @Romano, yes it's generating 100% , but I'm not able to compare it. – Badri Paudel Jun 03 '20 at 06:02
  • Don't as your logic is flawed. When using BCrypt the hash generated will differ (the value stored in the db) with each run. You can only compare if you already have the has and let BCrypt handle it. Also as you are using the `BCryptPasswordEncoder` you are already using Spring Security and this is basically working around Spring Security instead of working with it (or in other words you are making things harder for yourself instead of easier). Also comparing hashes doesn't change if you use Spring Boot or not, the mechanism is still the same (so that answer also applies!). – M. Deinum Jun 03 '20 at 07:22
  • If you run the following lines from the link I provided in my first comment using your pass and the hash you want to check: BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(); encoder.matches(password, user.getPassword()); What is the value returned by the second statement? – Romano Jun 03 '20 at 12:58
  • @M.Deinum well, I solved it , can you have a look and give me feedback. – Badri Paudel Jun 04 '20 at 05:42
  • @Romano well, I solved it , can you have a look and give me feedback ? – Badri Paudel Jun 04 '20 at 05:42

2 Answers2

0

I'm using this as an out of the box solution it's all managed by spring

@RestController
@RequestMapping("/api")
public class UserJWTController {



private final AuthenticationManagerBuilder authenticationManagerBuilder;

public UserJWTController( AuthenticationManagerBuilder authenticationManagerBuilder, 
....other dependancies) {
    //other dependancies
    this.authenticationManagerBuilder = authenticationManagerBuilder;
}

@PostMapping("/authenticate")
public ResponseEntity<JWTToken> authorize(@Valid @RequestBody LoginVM loginVM) {

    String authenticateWith = loginVM.getEmail()==null? 
  loginVM.getUsername():loginVM.getEmail();
    if(authenticateWith==null||authenticateWith.trim().isEmpty()) {
        return ResponseEntity.badRequest().build();
    }

    UsernamePasswordAuthenticationToken authenticationToken =
        new UsernamePasswordAuthenticationToken(authenticateWith.toLowerCase(), 
   loginVM.getPassword());

    Authentication authentication = 
  authenticationManagerBuilder.getObject().authenticate(authenticationToken);
    SecurityContextHolder.getContext().setAuthentication(authentication);
Hesham Osman
  • 111
  • 1
  • 1
  • 5
  • 1
    the imports are import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.core.Authentication; – Hesham Osman Jun 02 '20 at 16:21
0

I solved above problem this way. But, let me know if I can optimize solution in any other way.

@Override
public boolean getLoggedinUser(User user) {
    String uname = user.getUsername();
    String email = user.getEmail();
    String password = user.getPassword();

    BCryptPasswordEncoder bcryptEncoder = new BCryptPasswordEncoder();

    User userWithUsername = userRepo.findByUsername(uname);//as username is unique
    User userWithEmail = userRepo.findByEmail(email); //unique email

    String hashedPassword = "";

     if(userWithUsername !=null) {
        hashedPassword = userWithUsername.getPassword();
      System.out.println("------------" + userWithUsername + " _------------- " + hashedPassword);
     }

     else if(userWithEmail !=null) {
            hashedPassword = userWithEmail.getPassword();
          System.out.println("------------" + userWithUsername + " _------------- " + hashedPassword);
     }

    boolean isPasswordMatched = bcryptEncoder.matches(password, hashedPassword);

if(((userWithUsername ==null && userWithEmail != null ) && userWithEmail.isEnabled() == false) || ((userWithEmail ==null && userWithUsername !=null) && userWithUsername.isEnabled() == false)) {   
        return false;
    }

    if ((userRepo.findByUsername(uname) !=null && isPasswordMatched) || (userRepo.findByEmail(email) !=null && isPasswordMatched)) {
        return true;
    }
   return false;
}
Badri Paudel
  • 1,365
  • 18
  • 19
  • Looks like you are working around Spring Security. Why? – M. Deinum Jun 04 '20 at 05:46
  • @M.Deinum, yes but I also wanted to encrypt password of a user when he/she registers and later on implement whether that user exists or not, so I had to compare the password that user enters to the password that is encrypted and stored in db. Isn't this a good approach ? I'm kinda new to spring security. – Badri Paudel Jun 04 '20 at 08:37
  • No it isn't. Also why would you need to compare a password to see if someone already exists? Can you have the same username for 2 users but let them differ on password?! If you want to check an exist just let Spring Data handle it and write an method for it `existsByUsernameOrEmail(String username, String email)` which will return a `boolean` indicating if a record was found or not. – M. Deinum Jun 04 '20 at 08:58
  • @M.Deinum, yes you are right, but what I'm trying is to allow whether user to allow enter site or not? Allow only when user has username and password or email and password marched. Like , how Facebook allows us to login, if have matching credentials. Correct me if I am wrong. – Badri Paudel Jun 04 '20 at 09:23
  • That is the task of Spring Security which you are bypassing now. Why use a security framework if you start to work around it? – M. Deinum Jun 04 '20 at 09:25
  • @M.Deinum , well thanks alot. I used security for endpoints using security, now I'll implement security. Thanks for information. – Badri Paudel Jun 04 '20 at 09:29