23

I'm trying to add a salt when adding a new user/pwd, but the docs seem to be missing how to do this.

Here's a basic example:

<authentication-manager>
    <authentication-provider user-service-ref="userDetailsService">
        <password-encoder hash="md5">
            <salt-source user-property="username"/>
        </password-encoder>
    </authentication-provider>
</authentication-manager>

You can see by the example that neither a custom salt or custom password encoder is used.

So, how would I wire the Salt in when adding a new user/pwd? I'd assume it would be something along the lines of:

@Autowired SaltSource saltSource;
protected void foo(final CustomUser user) {
    final PasswordEncoder encoder = new Md5PasswordEncoder();
    user.setPassword(encoder.encodePassword(user.getPassword(), saltSource));
}

However, since I am using the default salt/password encoders and I don't have a custom salt bean the autowire would fail.

Any clue how to make this work?

user973479
  • 1,629
  • 5
  • 26
  • 48

1 Answers1

34

You don't autowire the SaltSource when adding user. The SaltSource is an abstraction used by Spring to provide the source of the salt for password checking only.

To create a properly encoded password hash You just past the salt itself to the PasswordEncoder - the value of username property, not the SaltSource:

private PasswordEncoder encoder = new Md5PasswordEncoder();

public User createUser(String username, String plainTextPassword) {
    User u = new User();
    u.setUsername(username);
    u.setPassword(encoder.encodePassword(plainTextPassword, username));
    getEntityManager().persist(u); // optional
    return u;
}

Moreover the autowire of SaltSource won't work until it's defined as an inner bean. You could define the ReflectionSaltSource as top level bean and pass it's ID to the password-encoder, i.e.:

<bean id="saltSource"
    class="org.springframework.security.authentication.dao.ReflectionSaltSource"
    p:userPropertyToUse="username" />

<bean id="passwordEncoder" 
    class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />

<bean id="daoAuthenticationProvider"
    class="org.springframework.security.authentication.dao.DaoAuthenticationProvider"
    p:passwordEncoder-ref="passwordEncoder"
    p:saltSource-ref="saltSource"
    p:userDetailsService-ref="userDetailsService" />

<authentication-manager>
    <authentication-provider ref="daoAuthenticationProvider" />
</authentication-manager>

And then:

@Autowired private PasswordEncoder passwordEncoder;
@Autowired private SaltSource saltSource;

public CustomUserDetails createUser(String username, String plainTextPassword) {
    CustomUserDetails u = new CustomUserDetails();
    u.setUsername(username);
    u.setPassword(passwordEncoder.encodePassword(
            plainTextPassword, saltSource.getSalt(u)));
    getEntityNamager().persist(u); // optional
    return u;
} 
Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
Roadrunner
  • 6,661
  • 1
  • 29
  • 38
  • The newer code doesnt seem to work. I get the following: IllegalStateException: Cannot convert value of type [java.lang.String] to required type [org.springframework.security.authentication.encoding.PasswordEncoder] for property 'passwordEncoder': no matching editors or conversion strategy found – user973479 Nov 09 '11 at 18:11
  • I corrected the XML code - forgot the `-ref` suffix on references. – Roadrunner Nov 09 '11 at 18:24
  • 7
    Be careful when considering the use of the username as the salt source. If the username changes, the salt will change and the user won't be able to log in since the encoded password is against the previous username used as the salt. – th3morg Nov 14 '13 at 13:28