0

I am facing again the same problem with Spring Security: "password does not match stored value".

I import 4 accounts in my graph (I'm using SpringData/Neo4J) with my custom GraphPopulator class and try to log in with one ("fbiville"/"s3cret").

The authentication is configured as follows:

<beans:bean id="encoder" class="org.springframework.security.crypto.password.StandardPasswordEncoder">
    <beans:constructor-arg value="******" />
</beans:bean>

<beans:bean id="userService" class="com.lateralthoughts.devinlove.service.LoginService" />

<authentication-manager>
    <authentication-provider user-service-ref="userService">
        <password-encoder ref="encoder" />
    </authentication-provider>
</authentication-manager>

And the class in charge of persisting accounts is partially based on a custom SpringData repository implementation:

class PersonRepositoryImpl implements PersonRepositoryCustom {

    private final PasswordEncoder passwordEncoder;
    private final Neo4jOperations template;

    @Autowired
    public PersonRepositoryImpl(PasswordEncoder passwordEncoder,
                            Neo4jOperations template) {

        this.passwordEncoder = passwordEncoder;
        this.template = template;
    }

    @Override
    @Transactional
    public void persist(Person person) {
        person.setPassword(passwordEncoder.encode(person.getPassword()));
        template.save(person);
    }
}

Finally, the login process is configured as follows:

<http auto-config='true' use-expressions='true' realm="devinlove: love is just another algorithm">
    <form-login   login-page="/login"
                  default-target-url="/"
                  authentication-failure-url="/login" />
    <intercept-url pattern="/login" access="isAnonymous()" />
    <intercept-url pattern="/**" access="hasRole('USER')" />
</http>

I debugged the StandardPasswordEncoder at account creation and user login attempt, and I noticed the salts don't match, which obviously leads to an authentication error.

You can clone the repository if you wanna reproduce the problem.

Thanks in advance !

Rolf

fbiville
  • 8,407
  • 7
  • 51
  • 79
  • 2
    A pointer to an arbitrarily large amount of code is _not_ worth a thousand explanations. It's not worth even _one_. It _complements_ an explanation, as the act of writing the explanation helps you understand the problem better. – Donal Fellows Mar 31 '13 at 17:22
  • You are right, my apologies. Let me edit my initial message to give more details. – fbiville Apr 01 '13 at 05:28

1 Answers1

-1

You need to use org.springframework.security.authentication.encoding.PasswordEncoder implementation, rather then org.springframework.security.crypto.password.PasswordEncoder.

So you can simply use as the follows:

<authentication-manager>
    <authentication-provider user-service-ref="userService">
        <password-encoder hash="sha" base64="true">
            <!--Single salt - the very same as you are using in `encoder` instance-->
            <salt-source system-wide="********"/>
        </password-encoder>
    </authentication-provider>
</authentication-manager>

Note, that this will work properly with @Autowired properties, though there shouldn't be @Qualifier and beans have to be represented only once.

It exposes implementation of such interfaces: org.springframework.security.authentication.encoding.PasswordEncoder and org.springframework.security.authentication.dao.SaltSource.

So in your particular case it would look like as follows:

class PersonRepositoryImpl implements PersonRepositoryCustom {

    private final PasswordEncoder passwordEncoder;
    private final Neo4jOperations template;

    @Autowired
    public PersonRepositoryImpl(PasswordEncoder passwordEncoder,
                                SaltSource saltSource
                                Neo4jOperations template) {

        this.passwordEncoder = passwordEncoder;
        this.saltSource = saltSource;
        this.template = template;
    }

    @Override
    @Transactional
    public void persist(Person person) {
        person.setPassword(passwordEncoder.encode(person.getPassword(), saltSource));
        template.save(person);
    }
}
n1ckolas
  • 4,380
  • 3
  • 37
  • 43
  • Thx for your answer. I replaced my configuration with the one you mention and adapted PersonRepositoryImpl to use the right Spring Security package and I still end up with the same result :/ – fbiville Apr 01 '13 at 12:50
  • Does it return the same values for the same passwords? Have you checked that in DB? – n1ckolas Apr 01 '13 at 12:57
  • My bad, I mistook in some way. However, now, when I follow the configuration you pasted, I cannot get any PasswordEncoder instance injected nor SaltSource ones. Do you know what beans are actually exposed? – fbiville Apr 01 '13 at 13:15
  • This isn't a good answer. `org.springframework.security.crypto.password.PasswordEncoder` *is* the preferred interface for password encoding in Spring Security 3.1 and using a system-wide salt is not a good idea. [BCrypt](http://stackoverflow.com/a/8528804/241990) is a better choice. – Shaun the Sheep Apr 01 '13 at 15:35
  • @LukeTaylor thanks for notice. I just realized, that the actual problem might be in datastorage, i.e. in `neo4j` – n1ckolas Apr 02 '13 at 07:26