Summary
Provide a Migration from 4.x to 5.x guide
PasswordEncoder
In the meantime, please refer to [PasswordEncoder javadoc](https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/password/PasswordEncoder.html]. It refers to other implementations that will discuss migration strategies. For example, you can refer to MessageDigestPasswordEncoder javadoc if you used DigestPasswordEncoder.
Comment From: cemo
I have just start to migrate our existing code base to 5.x and hit some problems. Our users had their salt values on their user table and currently I can see that salt completely has disappeared. Also PasswordEncoder has gone. DaoAuthenticationProvider does not include a salt source and this might cause us to duplicate previous codes into our code base by extending DaoAuthenticationProvider. What is the best way to upgrade security configurations who are using salt source on user table on db to 5.x currently? I think this is a good addition for documentation as well.
Comment From: cemo
public class SaltedDaoAuthenticationProvider extends DaoAuthenticationProvider {
static class SaltedUsernamePasswordAuthenticationToken extends UsernamePasswordAuthenticationToken{
private Subject subject;
SaltedUsernamePasswordAuthenticationToken(Object principal, Object credentials,
Collection<? extends GrantedAuthority> authorities,
Subject subject) {
super(principal, credentials, authorities);
this.subject = subject;
}
@Override
public Object getCredentials() {
String salt = subject.getIdentity().getSalt();
SaltedSha256PasswordEncoder encoder = new SaltedSha256PasswordEncoder();
return encoder.encodePassword(super.getCredentials().toString(), salt);
}
}
protected void additionalAuthenticationChecks(UserDetails details, UsernamePasswordAuthenticationToken auth)
throws AuthenticationException {
if(details instanceof MyDetails){
auth = new SaltedUsernamePasswordAuthenticationToken(auth.getPrincipal(),
auth.getCredentials(),
auth.getAuthorities(),
(MyDetails) details);
}
super.additionalAuthenticationChecks(details, auth);
}
}
I have come up with such an implementation and I am fine now.
Comment From: rwinch
@cemo You need a data migration to migrate the salt to be part of the password to use the existing PasswordEncoder this is outlined in MessageDigestPasswordEncoder
Comment From: rodrigorodrigues
@cemo You need a data migration to migrate the salt to be part of the password to use the existing
PasswordEncoderthis is outlined in MessageDigestPasswordEncoder
Hi @rwinch, I'm trying to migrate from 3 o 5 but completely lost with the configuration, could you show an example please?
Spring 3
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider());
}
@Bean
public PasswordEncoder passwordEncoder() {
return new ShaPasswordEncoder(256);
}
@Bean
public DaoAuthenticationProvider authenticationProvider() throws Exception {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
ReflectionSaltSource saltSource = saltSource();
authenticationProvider.setSaltSource(saltSource);
return authenticationProvider;
}
@Bean
public ReflectionSaltSource saltSource() {
ReflectionSaltSource saltSource = new ReflectionSaltSource();
saltSource.setUserPropertyToUse("salt");
return saltSource;
}
}
The salt and password are saved on database in different fields.
Spring 5
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authenticationProvider());
}
@Bean
public DaoAuthenticationProvider authenticationProvider() throws Exception {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(passwordEncoder());
return authenticationProvider;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new MessageDigestPasswordEncoder();// What should be in the parameter or should I use StandardPasswordEncoder instead?
}
}
For the data migration if I save {salt}+password would be enough or do I need to do something else?
Thanks.
Comment From: rwinch
For the data migration if I save {salt}+password would be enough or do I need to do something else?
Yes first migrate to using {salt}+password and the new version of the PasswordEncoder. Once you have done that, upgrade to Security 5.
If you are still having issues and can put together a minimal sample, I'd be happy to help with the sample.
Comment From: rodrigorodrigues
Hi @rwinch ,
I have migrated the passwords and upgraded to Security 5 now got the following IllegalArgumentException: Detected a Non-hex character at 1 or 2 position at DaoAuthenticationProvider line 86, if you could help me on that I would really appreciate it, thanks
@Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder defaultEncoder = new StandardPasswordEncoder();
Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put("bcrypt", new BCryptPasswordEncoder());
DelegatingPasswordEncoder passworEncoder = new DelegatingPasswordEncoder(
"bcrypt", encoders);
passworEncoder.setDefaultPasswordEncoderForMatches(defaultEncoder);
return passworEncoder;
}
Exception
java.lang.IllegalArgumentException: Detected a Non-hex character at 1 or 2 position
at org.springframework.security.crypto.codec.Hex.decode(Hex.java:62) ~[spring-security-core-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at org.springframework.security.crypto.password.StandardPasswordEncoder.decode(StandardPasswordEncoder.java:105) ~[spring-security-core-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at org.springframework.security.crypto.password.StandardPasswordEncoder.matches(StandardPasswordEncoder.java:80) ~[spring-security-core-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at org.springframework.security.crypto.password.DelegatingPasswordEncoder.matches(DelegatingPasswordEncoder.java:198) ~[spring-security-core-5.0.8.RELEASE.jar:5.0.8.RELEASE]
at org.springframework.security.authentication.dao.DaoAuthenticationProvider.additionalAuthenticationChecks(DaoAuthenticationProvider.java:86) ~[spring-security-core-5.0.8.RELEASE.jar:5.0.8.RELEASE]
Comment From: rwinch
By invoking passworEncoder.setDefaultPasswordEncoderForMatches(defaultEncoder); any password that is not prefixed with a valid id will delegate to StandardPasswordEncoder with the entire password. So if you have something like {not-mapped}asdfsadfsd then {not-mapped}asdfsadfsd will be passed to StandardPasswordEncoder.
Comment From: rwinch
If you have a password that is {sha256}asdfsadfsd then the entire thing is going to be passed into StandardPasswordEncoder which will fail with an error like that. Instead, you should add StandardPasswordEncoder in the encoders map and avoid using setDefaultPasswordEncoderForMatches. If that doesn't help, please create a question on StackOverflow that contains the encoded password value you are having trouble with.
PasswordEncoder defaultEncoder = new StandardPasswordEncoder();
Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put("bcrypt", new BCryptPasswordEncoder());
encoders.put("sha256", new defaultEncoder);
return new DelegatingPasswordEncoder(
"bcrypt", encoders);
We try and discourage asking for help on GitHub as this makes it harder for users to find. In the future, please ask on StackOverflow. If you don't get help there, I don't mind pinging via GitHub issues with a link to StackOverflow.
Comment From: rodrigorodrigues
Hi @rwinch thanks for your help appreciated, I solved the issue using new MessageDigestPasswordEncoder("SHA-256") instead new StandardPasswordEncoder().
Comment From: aschatten
Related issue that causes the migration to fail if Spring Security OAuth lib is used and it saves Spring Security objects in a database: https://github.com/spring-projects/spring-security-oauth/issues/662
Comment From: rwinch
This can be closed as no longer relevant