How do I integrate an LDAP user with the PERSON table created by Spring Security in Grails?

We are creating a grails application where we want the user to log in using their Active Directory credentials. In addition, we want to give the business owner of this application the ability to control who has access to certain links (actions). Because of this, we are using the following plugins in our grails application:

  • Spring Security Core
  • Spring LDAP Security
  • Spring Security User Interface

Since we want the business user to be able to create personalized roles with specific permissions (actions) on the fly when needed, we believe that the best Spring Security Configuration is a database based query based on Requestmap

So far we have done the following:

  • We can successfully authenticate to Active Directory.
  • We were also able to create different request mappings for different roles (ROLE_XXX) via the spring-security-ui plugin interface

Problems / Questions

The spring-security-core plugin created the following tables:

  • PERSON
  • ORGAN
  • PERSON_AUTHORITY
  • REQUESTMAP

These are tables that support creating roles, assigning URLs to roles. However, the Person_Authoritity table as a convention name implies a lot of relationship between HUMAN and AUTHORITY (ROLE), since a person could potentially have more than one role. My problem is that I don't have a Person because the person already exists in Active Directory (external source) and it was not created in the application.

Is there a way to make the authenticated user a MEMBER? A Spring security solution requires a string or Person object, however you prefer to reference it.

I also posted a question here:

http://grails.1312388.n4.nabble.com/Issues-integrating-LDAP-Authentication-with-Requestmap-to-Secure-URLs-td4644040.html

Thank,

+1


source to share


1 answer


Therefore, you need to essentially map an AD user to Person.

Here are the 3 classes you need in src / groovy. Obviously modify them as needed:

    package yourpackagename

    import org.codehaus.groovy.grails.plugins.springsecurity.GrailsUser
    import org.springframework.security.core.GrantedAuthority

    class CustomUserDetails extends GrailsUser{
        final String firstName
        final String lastName

        CustomUserDetails(String username, String password, boolean enabled,
                          boolean accountNonExpired, boolean credentialsNonExpired,
                          boolean accountNonLocked,
                          Collection<GrantedAuthority> authorities,
                          long id, String firstName, String lastName) {
            super(username, password, enabled, accountNonExpired,
                    credentialsNonExpired, accountNonLocked, authorities, id)

            this.firstName = firstName
            this.lastName = lastName
        }
    }

package yourpackagenamehere

import org.codehaus.groovy.grails.plugins.springsecurity.GrailsUserDetailsService
import org.springframework.security.core.authority.GrantedAuthorityImpl
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.core.userdetails.UsernameNotFoundException
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils

class CustomUserDetailsService implements GrailsUserDetailsService {

    /**
     * Some Spring Security classes (e.g. RoleHierarchyVoter) expect at least one role, so
     * we give a user with no granted roles this one which gets past that restriction but
     * doesn't grant anything.
     */
    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 CustomUserDetails(user.username, user.password, user.enabled,
                    !user.accountExpired, !user.passwordExpired,
                    !user.accountLocked, authorities ?: NO_ROLES, user.id,
                    user.firstName, user.lastName)
        } as UserDetails
    }
}

package yourpackagenamehere

import groovy.sql.Sql

import org.springframework.ldap.core.DirContextAdapter
import org.springframework.ldap.core.DirContextOperations
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper
import org.springframework.security.core.authority.GrantedAuthorityImpl
import org.springframework.security.core.GrantedAuthority
import org.codehaus.groovy.grails.plugins.springsecurity.SpringSecurityUtils

import org.springframework.security.core.userdetails.UsernameNotFoundException
import org.springframework.security.authentication.DisabledException

class CustomUserDetailsContextMapper implements UserDetailsContextMapper {

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

    def dataSource

    @Override
    public CustomUserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<GrantedAuthority> authority) {

        username = username.toLowerCase()

        User user = User.findByUsername(username)

        String firstName = ctx.originalAttrs.attrs['givenname'].values[0]
        String lastName = ctx.originalAttrs.attrs['sn'].values[0]


        def roles

        User.withTransaction {

            if(!user){
                user = new User(username: username, enabled: true, firstName: firstName, lastName: lastName)
                user.save(flush: true)
            }
            else {
                user = User.findByUsername(username)
                user.firstName = firstName
                user.lastName = lastName
                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 CustomUserDetails(username, user.password, user.enabled, false, false, false, authorities, user.id, user.firstName, user.lastName)

        return userDetails
    }

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

      

In spring / resources.groovy config:



import yourpackagenamehere.CustomUserDetailsService
import yourpackagenamehere.CustomUserDetailsContextMapper
beans = {
    userDetailsService(CustomUserDetailsService)

    ldapUserDetailsMapper(CustomUserDetailsContextMapper) {
        dataSource = ref("dataSource")
    }
}

      

In the Config.groovy section, here are my settings:

grails.plugins.springsecurity.ldap.context.managerDn = 'CN=username,OU=People,DC=foo,DC=com'
grails.plugins.springsecurity.ldap.context.managerPassword = 'password'
grails.plugins.springsecurity.ldap.context.server = 'ldap://foo.com:389/'
grails.plugins.springsecurity.ldap.authorities.ignorePartialResultException = true
grails.plugins.springsecurity.ldap.search.base = 'ou=People,dc=foo,dc=com'
grails.plugins.springsecurity.ldap.search.filter="sAMAccountName={0}"
grails.plugins.springsecurity.ldap.search.searchSubtree = true
grails.plugins.springsecurity.ldap.auth.hideUserNotFoundExceptions = false
grails.plugins.springsecurity.ldap.search.attributesToReturn = null
grails.plugins.springsecurity.providerNames = ['ldapAuthProvider', 'anonymousAuthenticationProvider']
grails.plugins.springsecurity.ldap.mapper.userDetailsClass = 'CustomUserDetails'

grails.plugins.springsecurity.ldap.authorities.retrieveGroupRoles = true
grails.plugins.springsecurity.ldap.authorities.retrieveDatabaseRoles = true
grails.plugins.springsecurity.ldap.authorities.groupSearchBase ='dc=foo,dc=com'
grails.plugins.springsecurity.ldap.authorities.groupSearchFilter = 'member={0}' 

      

+6


source







All Articles