0

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

DaFoot
  • 1,475
  • 8
  • 29
  • 58
  • 1
    The BCryptPasswordEncoder uses a salt for each password, so you will never get the same hash for the same plaintext (which is what you want). So to me it looks like the whole thing works as expected. Or what specific issue do you have besides the different hashes? – dunni Apr 11 '21 at 18:25
  • Thank you for the comments, that goes a good way to reassuring me things are working correctly. I guess I read too much into the blog post. – DaFoot Apr 11 '21 at 21:05

0 Answers0