Have simple Spring Security webapp with password encoding:
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="personService">
<security:password-encoder hash="md5" ref="passwordEncoder">
<!-- <security:salt-source user-property="username"/> -->
</security:password-encoder>
</security:authentication-provider>
</security:authentication-manager>
Encoding also simple:
person.setPassword(encoder.encodePassword(person.getPassword(), null));
So in DataBase all passwords will be encoded. Now I want to do authentication of some user with certain username within the apllication. Before(when passswords was in plaintext) it was like this:
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
username, password);
Authentication authentication = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
But now I get encoded password from DB and cant do authentication as before.
The problem. that Spring dont know that password cames from UsernamePasswordAuthenticationToken already encoded. And he is encoding it it second time. Who can help?
Edit
So I see two solutions here:
Any others? What is the best?
Spring Security supports many password encoders, for both old and modern algorithms. Also, Spring Security provides methods to work with multiple password encodings in the same application.
Simply put, Spring Security hold the principal information of each authenticated user in a ThreadLocal – represented as an Authentication object. In order to construct and set this Authentication object – we need to use the same approach Spring Security typically uses to build the object on a standard authentication.
Password Hashing With Spring Security Luckily for us, Spring Security ships with support for all these recommended algorithms via the PasswordEncoder interface: Pbkdf2PasswordEncoder gives us PBKDF2. BCryptPasswordEncoder gives us BCrypt, and. SCryptPasswordEncoder gives us SCrypt.
Instead of using just the password as input to the hash function, random bytes (known as salt) would be generated for every users' password. The salt and the user's password would be ran through the hash function which produced a unique hash. The salt would be stored alongside the user's password in clear text.
You haven't actually said what goes wrong, but the authentication code should be exactly the same as for the non-hashed version.
If you have a hashed password in the database and the corresponding encoder injected into the authentication provider, the password supplied by the user will be hashed by the encoder before comparing it with the database version.
Make sure:
UsernamePasswordAuthenticationToken
Also, you should probably choose something better than plain MD5. You might want to look at bcrypt, for example, which is supported in Spring Security 3.1 and automatically uses a random salt value.
Update
Your suggestion of creating a provider which accepts hashed passwords is not a good one. This would allow anyone who steals a password hash to authenticate with it directly (thus defeating the purpose of hashing in the first place).
Just validate your email URL links, load the information for that user and create an Authentication
object for them:
UserDetails user = ... // load user here
Authentication a = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(a);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With