Автоматическое создание пользовательских данных с помощью Grails и LDAP - PullRequest
1 голос
/ 01 апреля 2010

Я использую плагин Acegi Security для Grails и аутентификацию через 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 Ответ

2 голосов
/ 02 апреля 2010

Конечно.Вам необходимо реализовать собственный 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

Вы можете реализовать пользовательский UserDetailsService:

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); } }
...