Spring Security Salt

user973479 picture user973479 · Nov 9, 2011 · Viewed 23.2k times · Source

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?

Answer

Roadrunner picture Roadrunner · Nov 9, 2011

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;
}