I'm in the process of trying to add Spring Security to a SpringBoot powered application. I have (I think) the user service etc in place and trying to get login working.
To that end I have created a method (in a class activated by profile, it is running) to add some users to my data store...
@PostConstruct
public void deleteAllExistingAndAddDummyUsers() {
repo.findAll().forEach(repo::delete);
var plainPwd = "password";
var encodedPwd = pwdEncoder.encode(plainPwd);
var roles = <snipped>
service.createEnabledUser("examiner", encodedPwd, roles);
roles = <snipped>
service.createEnabledUser("commission", encodedPwd, roles);
roles = <snipped>
service.createEnabledUser("admin", encodedPwd, roles);
}
In the service:
public User createEnabledUser(String username, String plainPassword, HashSet<Role> roles) {
var encodedUserPassword = passwordEncoder.encode(plainPassword);
LOG.debug("createEnabledUser pwd: {}", encodedUserPassword);
var user = User.builder()
.enabled(true)
.authorities(roles)
.username(username)
.password(encodedUserPassword)
.build();
return userRepository.save(user);
}
The passwordEncoder is injected by Spring, created in securityConfig. I have checked it is the same instance in all places (dummy data creator, service and securityConfig).
According to a Spring blog post the encoded form of "password" should be: "{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG"
(https://spring.io/blog/2017/11/01/spring-security-5-0-0-rc1-released#password-storage-format)
Whereas the output from the debug in method above is: createEnabledUser pwd: {bcrypt}$2a$10$ntmi/69UtyRd02.GzpM8EeCubuQCIRJzCKuC7c/feNs66Xcd7NaHa createEnabledUser pwd: {bcrypt}$2a$10$ZWjRUVk7E17ktvxhCouHa.pODrEHTjNq3Kb0Ov.G7jfGW2By0M2vO createEnabledUser pwd: {bcrypt}$2a$10$kndsUahgOBJRBweK/VJdP.BwKKKXlehx5qJpzHI3Jld649jojtdOe
None of the generated encodings match what I expect to see according to that blog post, but more confusing for me is that they are all different.
What would be a more appropriate/correct way to generate users, specifically the passwords?
Shortened version of my security config:
@Slf4j
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity( // enabling per method authentication annotations
securedEnabled = true,
jsr250Enabled = true,
prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// URL/role matching left out for brevity
}
@Bean
public PasswordEncoder delegatingPasswordEncoder() {
Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put("bcrypt", new BCryptPasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
encoders.put("scrypt", new SCryptPasswordEncoder());
DelegatingPasswordEncoder passwordEncoder = new DelegatingPasswordEncoder("bcrypt", encoders);
passwordEncoder.setDefaultPasswordEncoderForMatches(encoders.get("bcrypt"));
return passwordEncoder;
}
}
Dependencies: spring-boot-starter-security:2.4.4 brings in security-config/security-web:5.4.5