Some approaches for diagnosing spring-security-core login errors
If you use the Grails spring-security-core plugin and you’re unable to authenticate, it can be hard to know where to start looking for the cause. Often it’s due to confusion from older blog posts that tell you to explicitly hash the password when creating a user, e.g.
def user = new User(username: 'me', enabled: true, password: springSecurityService.encodePassword('password')).save()
But the generated User domain class auto-hashes your password for you, so you would just do this (I omitted setting enabled
since in 2.0 it defaults to true
):
def user = new User(username: 'me', password: 'password').save()
If that isn’t the problem, Spring Security logs a lot at the debug level, so enable that in the log4j
block in Config.groovy
:
log4j = { ... debug 'org.springframework.security' }
With any luck there will be a useful signal in the noise and it’ll point you in the right direction.
If that doesn’t do it, you can configure a debugger and set a breakpoint in org.springframework.security.authentication.ProviderManager
in the authenticate
method. That’s where each registered AuthenticationProvider
gets a chance to attempt an authentication if it supports the current Authentication
.
Not everyone likes to use a debugger though. Another option is to register an event listener and look at the failure events. This is described in the plugin docs here. Here’s a simple configuration that will print information to the console for all failure events:
grails.plugin.springsecurity.useSecurityEventListener = true grails.plugin.springsecurity.onAbstractAuthenticationFailureEvent = { e, appCtx -> println "\nERROR auth failed for user $e.authentication.name: $e.exception.message\n" }
This is a great tip and helped me solve an error I made configuring Spring Security.
I’ve found that doing all three (or at least having the ability to do all three) is the best way to attack just about _any_ tricky problem involving the spring security family of plugins.
Though I will say that specifying the event handler directly in the config is a trick I hadn’t thought of. Instead, I created a listener class, which allows me to turn it’s logging on / off during runtime via the logging control mechanisms, which is nice.
I added the event handler directly to the config and it shed some more light on the error:
uthentication.ProviderManager – Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
ERROR auth failed for user admin: The specified user domain class ‘SecUser.SecRole’ is not a domain class
2014-09-30 18:48:43,076 [http-bio-9191-exec-6] DEBUG rememberme.TokenBasedRememberMeServices – Interactive login attempt was unsuccessful.
2014-09-30 18:48:43,076 [http-bio-9191-exec-6] DEBUG rememberme.TokenBasedRememberMeServices – Cancelling cookie
2014-09-30 18:48:43,099 [http-bio-9191-exec-6] DEBUG web.DefaultRedirectStrategy – Redirecting to ‘/shareRef/login/authfail?login_error=1’
I’m not sure why springsecurity indicates that SecUser.SecRole is not a domain class.