One more approach for diagnosing spring-security-core login errors
Thursday, January 30th, 2014I wrote up a few techniques to help determine what is happening when you are unable to authenticate with use the Grails spring-security-core plugin here
and since then I’ve had to use them myself a couple of times. I have everything configured to easily debug the issues and often that ends up being the best approach, but not everyone is comfortable with a debugger, or not excited about the prospect of configuring their IDE with JAR sources and the other steps needed to properly debug. This and this Stack Overflow question
prompted me to document another approach.
This one is a rather dangerous and should be removed as soon as the issue is resolved because it prints cleartext passwords to the console, which is a huge security risk.
There are a handful of places where the cleartext password is available, but I think the most convenient is in the additionalAuthenticationChecks
method of DaoAuthenticationProvider
. The arguments to the method are the UserDetails
instance, which will have the hashed password from the database, and the UsernamePasswordAuthenticationToken
which will have the cleartext password.
To access this, create a subclass of DaoAuthenticationProvider
:
package deletethisasap import org.springframework.security.authentication.UsernamePasswordAuthenticationToken as UPAT import org.springframework.security.authentication.dao.DaoAuthenticationProvider import org.springframework.security.core.Authentication import org.springframework.security.core.AuthenticationException import org.springframework.security.core.userdetails.UserDetails class MyDaoAuthenticationProvider extends DaoAuthenticationProvider { protected void additionalAuthenticationChecks(UserDetails ud, UPAT auth) throws AuthenticationException { String hashedPassword = passwordEncoder.encodePassword( auth.credentials, null) boolean ok = passwordEncoder.isPasswordValid( ud.password, auth.credentials, null) println "Cleartext: '$auth.credentials' from DB: '$ud.password' hashed '$hashedPassword' Valid: $ok" super.additionalAuthenticationChecks ud, auth } }
and register it with the same bean name in grails-app/conf/spring/resources.groovy
:
import deletethisasap.MyDaoAuthenticationProvider beans = { daoAuthenticationProvider(MyDaoAuthenticationProvider) { userDetailsService = ref('userDetailsService') passwordEncoder = ref('passwordEncoder') userCache = ref('userCache') saltSource = ref('saltSource') preAuthenticationChecks = ref('preAuthenticationChecks') postAuthenticationChecks = ref('postAuthenticationChecks') authoritiesMapper = ref('authoritiesMapper') hideUserNotFoundExceptions = true } }
It prints the hashed password and the cleartext password, and the cleartext password hashed for comparison. This won’t necessarily be the same as the value from the database, for example when using bcrypt, but the encoder has an isPasswordValid
method to verify that they’re equivalent, so that is also printed.
This code assumes that you’re using standard form-based authentication (i.e. DaoAuthenticationProvider
) and that you’re not using a salt. If you are using salted passwords, dependency-inject the saltSource
bean and use it in the encodePassword
and isPasswordValid
methods.