Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use new PasswordEncoder from Spring Security

As of Spring Security 3.1.4.RELEASE, the old org.springframework.security.authentication.encoding.PasswordEncoder has been deprecated in favour of org.springframework.security.crypto.password.PasswordEncoder. As my application has not been released to the public yet, I decided to move to the new, not deprecated API.

Until now, I had a ReflectionSaltSource that automatically used the user's registration date as per-user salt for password.

String encodedPassword = passwordEncoder.encodePassword(rawPassword, saltSource.getSalt(user));

During login process, Spring also used my beans to appropriate verify if the user can or can not sign in. I can't achieve this in the new password encoder, because the default implementation of SHA-1 - StandardPasswordEncoder has only ability to add a global secret salt during the encoder creation.

Is there any reasonable method of how to set it up with the non-deprecated API?

like image 429
fracz Avatar asked Jul 03 '13 09:07

fracz


People also ask

What is PasswordEncoder in Spring Security?

We use the PasswordEncoder that is defined in the Spring Security configuration to encode the password. In this example, the passwords are encoded with the bcrypt algorithm because we set the PasswordEncoder as the password encoder in the configuration. The code just saves the new user to the database.

How do I use BCryptPasswordEncoder in Spring Security?

@Autowired private BCryptPasswordEncoder bCryptPasswordEncoder; @GetMapping("/test") public void fillDatabse() { String encodedPw=bCryptPasswordEncoder. encode("test"); Password p = new Password(encodedPw);

What can I use instead of NoOpPasswordEncoder?

Class NoOpPasswordEncoder. Deprecated. This PasswordEncoder is not secure. Instead use an adaptive one way function like BCryptPasswordEncoder, Pbkdf2PasswordEncoder, or SCryptPasswordEncoder.


4 Answers

If you haven't actually registered any users with your existing format then you would be best to switch to using the BCrypt password encoder instead.

It's a lot less hassle, as you don't have to worry about salt at all - the details are completely encapsulated within the encoder. Using BCrypt is stronger than using a plain hash algorithm and it's also a standard which is compatible with applications using other languages.

There's really no reason to choose any of the other options for a new application.

like image 61
Shaun the Sheep Avatar answered Oct 12 '22 09:10

Shaun the Sheep


Here is the implementation of BCrypt which is working for me.

in spring-security.xml

<authentication-manager >     <authentication-provider ref="authProvider"></authentication-provider>       </authentication-manager> <beans:bean id="authProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">   <beans:property name="userDetailsService" ref="userDetailsServiceImpl" />   <beans:property name="passwordEncoder" ref="encoder" /> </beans:bean> <!-- For hashing and salting user passwords -->     <beans:bean id="encoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/> 

In java class

PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); String hashedPassword = passwordEncoder.encode(yourpassword); 

For more detailed example of spring security Click Here

Hope this will help.

Thanks

like image 32
Ravi Kant Avatar answered Oct 12 '22 09:10

Ravi Kant


I had a similar issue. I needed to keep the legacy encrypted passwords (Base64/SHA-1/Random salt Encoded) as users will not want to change their passwords or re-register. However I wanted to use the BCrypt encoder moving forward too.

My solution was to write a bespoke decoder that checks to see which encryption method was used first before matching (BCrypted ones start with $).

To get around the salt issue, I pass into the decoder a concatenated String of salt + encrypted password via my modified user object.

Decoder

@Component
public class LegacyEncoder implements PasswordEncoder {

    private static final String BCRYP_TYPE = "$";
    private static final PasswordEncoder BCRYPT = new BCryptPasswordEncoder();

    @Override
    public String encode(CharSequence rawPassword) {

    return BCRYPT.encode(rawPassword);
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {

    if (encodedPassword.startsWith(BCRYP_TYPE)) {
        return BCRYPT.matches(rawPassword, encodedPassword);
    }

    return sha1SaltMatch(rawPassword, encodedPassword);
    }

    @SneakyThrows
    private boolean sha1SaltMatch(CharSequence rawPassword, String encodedPassword) {

    String[] saltHash = encodedPassword.split(User.SPLIT_CHAR);

    // Legacy code from old system   
    byte[] b64salt = Base64.getDecoder().decode(saltHash[0].getBytes());
    byte[] validHash = Base64.getDecoder().decode(saltHash[1]);
    byte[] checkHash = Utility.getHash(5, rawPassword.toString(), b64salt);

    return Arrays.equals(checkHash, validHash);
    }

}

User Object

public class User implements UserDetails {

    public static final String SPLIT_CHAR = ":";

    @Id
    @Column(name = "user_id", nullable = false)
    private Integer userId;

    @Column(nullable = false, length = 60)
    private String password;

    @Column(nullable = true, length = 32)
    private String salt;

.
.

    @PostLoad
    private void init() {

    username = emailAddress; //To comply with UserDetails
    password = salt == null ? password : salt + SPLIT_CHAR + password;
    }        

You can also add a hook to re-encode the password in the new BCrypt format and replace it. Thus phasing out the old method.

like image 37
Simon Jenkins Avatar answered Oct 12 '22 10:10

Simon Jenkins


Having just gone round the internet to read up on this and the options in Spring I'd second Luke's answer, use BCrypt (it's mentioned in the source code at Spring).

The best resource I found to explain why to hash/salt and why use BCrypt is a good choice is here: Salted Password Hashing - Doing it Right.

like image 20
user2546977 Avatar answered Oct 12 '22 09:10

user2546977