I am migrating Spring security from 4.2.16.RELEASE
to 5.6.3
version.
The existing project security configuration uses deprecated ShaPasswordEncoder
and custom SaltSource
for the salt generation. The salt is comprised of application configuration property and user's uuid:
<bean id="customAuthenticationProvider" >
<property name="userDetailsService" ref="CustomUserDetailsService" />
<property name="saltSource" ref="saltSource" />
<property name="passwordEncoder" ref="passwordEncoder" />
<property name="servicesURL" value="${custom.services.url}" />
</bean>
<bean id="passwordEncoder" >
<constructor-arg value="256" />
</bean>
<bean id="saltSource" >
<property name="userPropertyToUse" value="CustomId" />
<property name="systemWideSalt" value="${security.systemwide.salt}" />
</bean>
The getSalt
method:
public Object getSalt(String secondSaltProperty) {
try {
return secondSaltProperty this.systemWideSalt;
} catch (Exception exception) {
throw new AuthenticationServiceException(exception.getMessage(),
exception);
}
}
My goal is not only migrate to newer Spring security version but also start using the recommended BCryptPasswordEncoder
password encoder.
According to the migration guide, I have to migrate the existing passwords:
The format is intended to work with the DigestPasswordEncoder that was found in the Spring Security core module. However, the passwords will need to be migrated to include any salt with the password since this API provides Salt internally vs making it the responsibility of the user. To migrate passwords from the SaltSource use the following: String salt = saltSource.getSalt(user); String s = salt == null ? null : "{" salt "}"; String migratedPassword = s user.getPassword();
Question: The thing that I am not clear about the password migration part is combining the new password storage format {id}encodedPassword
, where id
is used for selecting corresponding password encoder, and the salt part.
According to the migration guide I have to add {sha256}
prefix to the stored passwords, so the DelegatingPasswordEncoder
will pick up the proper decoder, but how to deal with the salt
part then?
My understanding is the following:
First I have to define the DelegatingPasswordEncoder
and if I don't add the id
prefix to the password I have to set the default password encoder using DelegatingPasswordEncoder.setDefaultPasswordEncoderForMatches
method to pick up the old password encoder.
Next, authentication logic is implemented in the custom AuthenticationProvider
service class, in which passwordEncoder
is injected and used for password matching check. Before calling the PasswordEncoder.matches(CharSequence rawPassword, String encodedPassword);
, I have to add the code that will format the encoded password to match the {salt}password
format.
Next step is to add Successful authentication listener that will re-encode the passwords to match the {bcrypt}password
format and store it into DB. So on the next user log in attempt the BCryptPasswordEncoder
password encoder will be invoked instead.
Once all passwords will be migrated, I will be able to delete the custom SaltSource-wise stuff and the Successful authentication listener.
Pls, correct me if I am wrong or if I am missing something. Thanks.
CodePudding user response:
There are only 2 things you need to do.
- Migrate the passwords to include the salt in the pattern
{salt}<password-hash>
- Configure the
DelegatingPasswordEncoder
and set the, properly configured,MessageDigestPasswordEncoder
as the default. So if no encoding is specified it will fallback to that one.
If you want to convert the passwords on the fly you could do that with a succes handler and update the record to use BCrypt/SCrypt instead of what you have now.