Why can't i login with spring security and weceem plugin installed in grails framework 1.3.7
I'm working on a nearly clean grails 1.3.7 project with weceem 1.0RC2, spring-security-core 1.1.3, spring-security-ui 0.1.2, weceem-spring-security 1.0 and their dependencies installed.
Everything works fine except the user login. When I want to login over http://localhost:8080/appname/login i only get the following error message:
Sorry, we were not able to find a user with that username and password.
But the user still exists in the database and i get the same error message if i use a user created by spring-security-ui. To encode passwords i'm using springSecurityService.encodePassword('password'). The LoginController was generated by spring-security (s2-quickstart).
I think there could be a problem with the weceem - spring-security bridge, what's your oppinion?
Best regards, whitenexx
import grails.converters.JSON
import javax.servlet.http.HttpServletResponse
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils
import org.springframework.security.authentication.AccountExpiredException
import org.springframework.security.authentication.CredentialsExpiredException
import org.springframework.security.authentication.DisabledException
import org.springframework.security.authentication.LockedException
import org.springframework.security.core.context.SecurityContextHolder as SCH
import org.springframework.security.web.WebAttributes
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
class LoginController {
/**
* Dependency injection for the authenticationTrustResolver.
*/
def authenticationTrustResolver
/**
* Dependency injection for the springSecurityService.
*/
def springSecurityService
/**
* Default action; redirects to 'defaultTargetUrl' if logged in, /login/auth otherwise.
*/
def index = {
if (springSecurityService.isLoggedIn()) {
redirect uri: SpringSecurityUtils.securityConfig.successHandler.defaultTargetUrl
}
else {
redirect action: auth, params: params
}
}
/**
* Show the login page.
*/
def auth = {
def config = SpringSecurityUtils.securityConfig
if (springSecurityService.isLoggedIn()) {
redirect uri: config.successHandler.defaultTargetUrl
return
}
String view = 'auth'
String postUrl = "${request.contextPath}${config.apf.filterProcessesUrl}"
render view: view, model: [postUrl: postUrl,
rememberMeParame开发者_高级运维ter: config.rememberMe.parameter]
}
/**
* The redirect action for Ajax requests.
*/
def authAjax = {
response.setHeader 'Location', SpringSecurityUtils.securityConfig.auth.ajaxLoginFormUrl
response.sendError HttpServletResponse.SC_UNAUTHORIZED
}
/**
* Show denied page.
*/
def denied = {
if (springSecurityService.isLoggedIn() &&
authenticationTrustResolver.isRememberMe(SCH.context?.authentication)) {
// have cookie but the page is guarded with IS_AUTHENTICATED_FULLY
redirect action: full, params: params
}
}
/**
* Login page for users with a remember-me cookie but accessing a IS_AUTHENTICATED_FULLY page.
*/
def full = {
def config = SpringSecurityUtils.securityConfig
render view: 'auth', params: params,
model: [hasCookie: authenticationTrustResolver.isRememberMe(SCH.context?.authentication),
postUrl: "${request.contextPath}${config.apf.filterProcessesUrl}"]
}
/**
* Callback after a failed login. Redirects to the auth page with a warning message.
*/
def authfail = {
def username = session[UsernamePasswordAuthenticationFilter.SPRING_SECURITY_LAST_USERNAME_KEY]
String msg = ''
def exception = session[WebAttributes.AUTHENTICATION_EXCEPTION]
if (exception) {
if (exception instanceof AccountExpiredException) {
msg = SpringSecurityUtils.securityConfig.errors.login.expired
}
else if (exception instanceof CredentialsExpiredException) {
msg = SpringSecurityUtils.securityConfig.errors.login.passwordExpired
}
else if (exception instanceof DisabledException) {
msg = SpringSecurityUtils.securityConfig.errors.login.disabled
}
else if (exception instanceof LockedException) {
msg = SpringSecurityUtils.securityConfig.errors.login.locked
}
else {
msg = SpringSecurityUtils.securityConfig.errors.login.fail
}
}
if (springSecurityService.isAjax(request)) {
render([error: msg] as JSON)
}
else {
flash.message = msg
redirect action: auth, params: params
}
}
/**
* The Ajax success redirect url.
*/
def ajaxSuccess = {
render([success: true, username: springSecurityService.authentication.name] as JSON)
}
/**
* The Ajax denied redirect url.
*/
def ajaxDenied = {
render([error: 'access denied'] as JSON)
}
}
I just resolved a problem with identical symptoms.
It turned out that the mapping closure I had in my Config.groovy had a typo, and I was mapping a field that didn't exist to the 'password' field in the weceem view of the user.
So the custom UserDetailsService injected by the plugin just hated my user objects, and nothing worked right.
I changed passwd to password on the domain side of the mapping to make it match what was actually in my User object, and all was right with the world.
Its a bit tricky to tell from the little info you have provided. The Weceem Spring Security plugin bridges Spring Security Core to Weceem's authentication mechanism.
It does this by providing a custom UserDetailsService implementation that maps from a domain class to the session data object used by Spring Security Core.
This login URL, is it mapped to your own login controller detailed above? The UserDetailsService in the weceem-spring-security plugin uses the configured user domain class to call findByUsername(username):
void afterPropertiesSet() {
def conf = grailsApplication.config
def clsname = conf.grails.plugins.springsecurity.userLookup.userDomainClassName
domainClass = grailsApplication.getDomainClass(clsname).clazz
def mapper = conf.weceem.springsecurity.details.mapper
if (!(mapper instanceof Closure)) {
throw new IllegalArgumentException(
"Your Config must specify a closure in weceem.springsecurity.details.mapper "+
"that maps the domain model to a non-domain object, providing at least: ${REQUIRED_MAPPED_FIELDS}")
}
detailsMapper = mapper
}
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
domainClass.withTransaction { status ->
def user = domainClass.findByUsername(username)
if (!user) throw new UsernameNotFoundException('User not found', username)
...
So as you can see from the above, I think that last line may be where it is ditching out for you, due to some spring domain class / username issue?
If the problem is related to logging into Weceem once installed (which it doesn't appear to be) you need to make sure you have configured how Weceem Spring Security should map from your user domain class to the internal data needed by weceem and spring sec core to function, see:
http://grails.org/plugin/weceem-spring-security
精彩评论