Grails Spring Security LDAP

会有一股神秘感。 提交于 2019-12-13 04:28:36

问题


I've been banging my head on a wall try to map a grails user authenticated against LDAP to the database Roles and Users in the application. Following the examples in this answer and the documentation.

If I don't include the bean ldap auth works, but there are many ties in the GORM to a user for creates and updates.

I keep reaching the point where my CustomUserDetails cannot cast to the UserDetails.

Message: Cannot cast object 'ldap_username' with class 'package.MdtUserDetails' to class 'org.springframework.security.core.userdetails.UserDetails'

The error occurs in the UserDetailsContextMapper Class, when calling MdtUserDetails:

import java.util.Collection;
import org.springframework.ldap.core.DirContextAdapter
import org.springframework.ldap.core.DirContextOperations
import org.springframework.security.authentication.DisabledException
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.authority.GrantedAuthorityImpl
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper
import grails.plugin.springsecurity.SpringSecurityUtils
import package.User
import package.Role
import package.UserRole


class MdtUserDetailsContextMapper implements UserDetailsContextMapper { 

    private static final List NO_ROLES = [new GrantedAuthorityImpl(SpringSecurityUtils.NO_ROLE)]

    def dataSource


    @Override
    public UserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<GrantedAuthority> authority) {
        username = username.toLowerCase()

        User user = User.findByUsername(username)

        String ldapName = ctx.originalAttrs.attrs['name']
        String ldapEmail = ctx.originalAttrs.attrs['mail']
        String splitName = ldapName.split(": ")[1]
        String fullname = splitName.split(", ")[1] + " " + splitName.split(", ")[0]
        String email = ldapEmail.split(": ")[1]

        def roles

        User.withTransaction {

            if(!user){
               user = new User(username: username, enabled: true, fullName: fullname, email: email).save(flush: true)
               UserRole.create user, Role.findByAuthority('ROLE_USER'), true
               roles = Role.findByAuthority('ROLE_USER')
            }
            else {
            user = User.findByUsername(username)
               user.fullName = fullname
               user.email = email
               user.save(flush: true)
               roles = user.getAuthorities()
           }


        }

        if ( !user.enabled )
        throw new DisabledException("User is disabled", username)


        def authorities = roles.collect { new GrantedAuthorityImpl(it.authority) }
        authorities.addAll(authority)

        def userDetails = new MdtUserDetails(fullname, email, username, "", true, false, false, false, authorities)  //the error is here...


        return userDetails
    }

    @Override
    public void mapUserToContext(UserDetails arg0, DirContextAdapter arg1) {
    }

}

here is my resources.goovy

import package.MdtUserDetailsContextMapper
import package.MdtUserDetailsService

beans = {       
    ldapUserDetailsMapper(MdtUserDetailsContextMapper) {
        dataSource = ref("dataSource")
    }

    UserDetailsService(MdtUserDetailsService)
}

config.groovy:

grails.plugin.springsecurity.ldap.context.managerDn = 'cn=MDT Apache,ou=ServiceAccounts,ou=Users,ou=MDT,dc=mdthq,dc=mt,dc=ads'
grails.plugin.springsecurity.ldap.context.managerPassword = '*******'
grails.plugin.springsecurity.ldap.context.server = 'ldap://server:389'
grails.plugin.springsecurity.ldap.authorities.groupSearchBase = 'ou=Groups,ou=MDT,dc=mdthq,dc=mt,dc=ads'
grails.plugin.springsecurity.ldap.search.base = 'ou=Users,ou=MDT,dc=mdthq,dc=mt,dc=ads'
grails.plugin.springsecurity.ldap.authorities.retrieveGroupRoles = true
grails.plugin.springsecurity.ldap.authorities.retrieveDatabaseRoles = true
grails.plugin.springsecurity.ldap.mapper.userDetailsClass = 'package.MdtUserDetails'
grails.plugin.springsecurity.ldap.authorities.ignorePartialResultException = true // typically needed for Active Directory
grails.plugin.springsecurity.ldap.search.filter="sAMAccountName={0}" // for Active Directory you need this
grails.plugin.springsecurity.ldap.search.searchSubtree = true
grails.plugin.springsecurity.ldap.auth.hideUserNotFoundExceptions = false
grails.plugin.springsecurity.ldap.search.attributesToReturn = ['mail', 'displayName', 'sAMAccountName'] // extra attributes you want returned; see below for custom classes that access this data
grails.plugin.springsecurity.ldap.authorities.groupSearchFilter = '(member:1.2.840.113556.1.4.1941:={0})'
//check against LDAP first, then Database
grails.plugin.springsecurity.providerNames = ['ldapAuthProvider', 'daoAuthenticationProvider'] 

Then classes for UserDetails and UserDetailsService:

import java.util.Collection;
import org.springframework.security.core.GrantedAuthority
import package.User

class MdtUserDetails extends User {


    public MdtUserDetails(String fullName, String email, String username, String password, boolean enabled, boolean accountExpired,
        boolean accountLocked, boolean passwordExpired, Collection<GrantedAuthority> authorities) {


        super(username: username, password: password, email: email, fullName: fullName, enabled: enabled, accountExpired: accountExpired, accountLocked: accountLocked, passwordExpired: passwordExpired)

        this.fullName = fullName
        this.email = email


    }
}



 import package.User
    import grails.plugin.springsecurity.userdetails.GrailsUserDetailsService
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.GrantedAuthorityImpl
    import org.springframework.security.core.userdetails.UserDetails
    import org.springframework.security.core.userdetails.UsernameNotFoundException



    import grails.plugin.springsecurity.SpringSecurityUtils

    class MdtUserDetailsService implements GrailsUserDetailsService {

       static final List NO_ROLES = [new GrantedAuthorityImpl(SpringSecurityUtils.NO_ROLE)]


       UserDetails loadUserByUsername(String username, boolean loadRoles)
                throws UsernameNotFoundException {

                    return loadUserByUsername(username)
       }

       UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

          User.withTransaction { status ->

                User user = User.findByUsername(username)
                if (!user) throw new UsernameNotFoundException('User not found', username)

                def authorities = user.authorities.collect {new GrantedAuthorityImpl(it.authority)}

             return new MdtUserDetails(user.fullName, user.email, user.username, user.password, user.enabled,
                !user.accountExpired, !user.passwordExpired,
                !user.accountLocked, authorities ?: NO_ROLES)
           }  as UserDetails

       }
    }

Updated UserDetails:

import java.util.Collection;

import org.springframework.security.core.GrantedAuthority
import org.springframework.security.ldap.userdetails.LdapUserDetails

import package.Role
import package.User

class MdtUserDetails extends User implements LdapUserDetails{

    final String email
    final String fullName

    public MdtUserDetails(String fullName, String email, String username, String password, boolean enabled, boolean accountExpired,
        boolean accountLocked, boolean passwordExpired, Collection<GrantedAuthority> authorities) {

        //super(username: username)
        //super(username: username, password: password, email: email, fullName: fullName, enabled: enabled, accountExpired: accountExpired, accountLocked: accountLocked, passwordExpired: passwordExpired, authorties: authorities)
        this.fullName = fullName
        this.email = email


    }


    @Override 
    public Set<Role> getAuthorities(){
        return super.getAuthorities()
    }

    @Override
    public boolean isAccountNonExpired() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isAccountNonLocked() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public String getDn() {
        // TODO Auto-generated method stub
        return null;
    }


}

EDIT

Finally figured this out!

in the UserDetails class I was extending my own user class:

import package.User

class MdtUserDetails extends User {

Instead I needed to extend the springsecurity user class from here :

import org.springframework.security.core.userdetails.User

回答1:


MdtUserDetails needs to implement the UserDetails interface. Try something like this:

class MdtUserDetails extends User implements LdapUserDetails {
   ... //everything required by the interface
} 


来源:https://stackoverflow.com/questions/21335251/grails-spring-security-ldap

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!