使用Grails和LDAP自动创建用户详细信息

时间:2010-04-01 00:22:24

标签: java grails ldap spring-security

我正在使用Grails的Acegi Security插件,以及通过LDAP进行身份验证。

应用程序日志显示,在登录时,我们可以通过LDAP对用户进行身份验证并获取其角色,但登录失败,因为在应用程序的数据库中找不到用户详细信息。

有没有办法自动创建和保存基本的用户详细信息域对象(如果尚不存在)?

- 更新
以下是我目前看到的相关调试条目

DEBUG populator.DefaultLdapAuthoritiesPopulator  - Roles from search: [Role1, Role2, etc]
ERROR springsecurity.GrailsDaoImpl  - User not found: MyUserName
DEBUG rememberme.TokenBasedRememberMeServices  - Interactive login attempt was unsuccessful.

1 个答案:

答案 0 :(得分:2)

不确定。 您需要实现自定义AuthProvider

SecurityConfig.groovy:

security {
   providerNames = ['ldapAuthProvider']
}

Ldap Auth Provider:

import domain.user.AppUser
import org.apache.commons.codec.digest.DigestUtils
import org.apache.log4j.Logger
import org.codehaus.groovy.grails.plugins.springsecurity.GrailsUserImpl
import org.springframework.security.BadCredentialsException
import org.springframework.security.GrantedAuthority
import org.springframework.security.GrantedAuthorityImpl
import org.springframework.security.providers.UsernamePasswordAuthenticationToken
import org.springframework.security.providers.dao.AbstractUserDetailsAuthenticationProvider
import org.springframework.security.userdetails.UserDetails

/**
 * Authentication provider that checks user credentials against LDAP
 */
class LdapAuthProvider extends AbstractUserDetailsAuthenticationProvider {
    private static final Logger log = Logger.getLogger(LdapAuthProvider.class)

    def appUserService

    /**
     * Checks password hash stored in the session with password in authentication token.
     */
    protected void additionalAuthenticationChecks(UserDetails details,
        UsernamePasswordAuthenticationToken authentication) {

        if (details.password != DigestUtils.md5Hex(authentication.credentials)) {
            throw new BadCredentialsException(details.username)
        }
    }

    /**
     * Retrieves user from LDAP,
     * checks credentials,
     * updates local copy of user data,
     * returns user details.
     */
    protected UserDetails retrieveUser(String login, UsernamePasswordAuthenticationToken authentication) {
        AppUser.withTransaction {
            log.debug("Trying to retrieve user \"$login\"...")
            def password = authentication.credentials?.toString()

            def ldapUser = appUserService.findLdapUser(login)
            if (!(password && ldapUser?.authenticate(password))) {
                log.debug("Can't authenticate \"$login\"")
                throw new BadCredentialsException(login)
            }

            AppUser localUser = AppUser.findByLogin(login, [cache: true])

            if (!localUser) {
                log.debug("Can't authenticate \"$login\"")
                localUser = appUserService.updateLocalUser(ldapUser)
            }

            log.debug("User \"$login\" is authenticated.")
            def authorities = localUser.collectAuthorities().collect {String authority ->
                log.debug("\thas right \"$authority\"")
                new GrantedAuthorityImpl(authority)
            }

            def userDetails = new AppUser();
            userDetails.setAssignedTemplate(localUser.assignedTemplate)
            userDetails.setFullName(localUser.getFullName())
            userDetails.setLogin(localUser.getLogin())
            userDetails.setEmail(localUser.getEmail())
            userDetails.setDisabled(localUser.getDisabled())
            userDetails.setManager(localUser.getManager())
            userDetails.setRoles(new HashSet(localUser.getRoles()))


            log.debug("Retrieving user \"$login\" is completed.")
            return new GrailsUserImpl(userDetails.login, DigestUtils.md5Hex(password), true, true, true, true,
                authorities.toArray(new GrantedAuthority[authorities.size()]), userDetails)
        }
    }
}

appUserService.updateLocalUser(ldapUser)中,您需要创建/修改您的域对象并保留在数据库中。

AppUser updateLocalUser(LdapUser ldapUser) {
    def login = ldapUser.login
    log.debug("Start updating local user ${login}...")
    def localUser = AppUser.findByLogin(login, [cache: true]) ?: new AppUser()
    if (localUser.id) {
        log.debug("user $login was found in local DB")
        if (localUser.disabled ^ ldapUser.isDisabled()) {
            log.debug("...user ${login} has been ${localUser.disabled ? 'activated' : 'disabled'}...")
        }
    } else {
        log.debug("user $login is new")
    }
    localUser.login = login
    localUser.email = ldapUser.email
    localUser.fullName = ldapUser.fullName ?: login
    localUser.disabled = ldapUser.isDisabled();
    localUser.roles?.clear()
    ldapUser.memberOf.collect { Role.findByLdapName(it, [cache: true]) }.each {role ->
        if (role) {
            localUser.addToRoles(role)
        }
    };
    localUser.save(flush: true)
    log.debug("Update local user $login is complete.")
}

更新#1

您可以实现自定义UserDetailsS​​ervice:

package com.foo.bar;

import org.springframework.security.userdetails.UserDetails; import org.springframework.security.userdetails.UserDetailsService;

public class MyUserDetailsService implements UserDetailsService {

public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException, DataAccessException {

// lookup user and data

return new MyUserDetails(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities, id, fullName); } }