grails-plugins / grails-spring-security-ldap

Apache License 2.0
14 stars 28 forks source link

JWT Refresh Token does not work with grails-spring-security-ldap #22

Open dbaylerg opened 5 years ago

dbaylerg commented 5 years ago

grails 3.3.10

application.yml grails: plugin: springsecurity: ldap: context: managerDn: 'uid=admin,ou=system' managerPassword: 'secret' server: 'ldap://myldap' authorities: groupSearchBase: 'ou=Groups,ou=TPS,dc=example,dc=com' search: base: 'ou=Users,ou=TPS,dc=example,dc=com' rest: token: storage: jwt: secret: 'myjwttokensecret'

build.gradle compile 'org.grails.plugins:spring-security-core:3.2.3' compile "org.grails.plugins:spring-security-rest:2.0.0.RC1" compile 'org.grails.plugins:spring-security-ldap:3.0.2'

I am using JWT Token generation from org.grails.plugins:spring-security-rest after authenticating with Apache Directory Server.

I use the login endpoint "/api/login" to get a JWT token which works.
I use the validate endpoint "/api/validate" to validate the JWT Token which also works.

The problem is the "/oauth/access_token" endpoint always returns 403 because an exception is thrown.

Here is what I believe to be the issues:

line 55 in grails.plugin.springsecurity.rest.token.storage.jwt.JwtTokenStorageService is "UserDetails principal = userDetailsService.loadUserByUsername(jwt.JWTClaimsSet.subject)"

The userDetailsService that is injected is an instance of GormUserDetailsManager when I would have expected to be an instance of GrailsLdapUserDetailsManager or some other LDAP implementation.

Is this something this Ldap Plugin should be injecting?

dbaylerg commented 5 years ago

Related issue? https://github.com/alvarosanchez/grails-spring-security-rest/issues/396

amsakni commented 4 years ago

work around:

import grails.plugin.springsecurity.ldap.userdetails.GrailsLdapUserDetailsManager
import grails.plugin.springsecurity.userdetails.GrailsUserDetailsService
import groovy.transform.CompileStatic
import org.apache.commons.logging.Log
import org.apache.commons.logging.LogFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.ldap.core.ContextSource
import org.springframework.ldap.core.DirContextOperations
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.ldap.search.LdapUserSearch
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper

@CompileStatic
class LdapUserDetailsManagerImpl extends GrailsLdapUserDetailsManager  implements GrailsUserDetailsService {

    private final Log logger = LogFactory.getLog(LdapUserDetailsManagerImpl.class)

    @Autowired
    private LdapAuthoritiesPopulator authoritiesPopulator

    @Autowired
    private LdapUserSearch userSearch;

    @Autowired
    private UserDetailsContextMapper ldapUserDetailsMapper;

    LdapUserDetailsManagerImpl(ContextSource contextSource) {
        super(contextSource)
    }

    private Collection<? extends GrantedAuthority> loadUserAuthorities(
            DirContextOperations userData, String username) {
        return authoritiesPopulator.getGrantedAuthorities(userData, username)
    }

    @Override
    UserDetails loadUserByUsername(String username) {
        logger.debug("Loading user '" + username)

        DirContextOperations userFromSearch = userSearch.searchForUser(username)
        List<GrantedAuthority> authorities = (List<GrantedAuthority>) loadUserAuthorities(userFromSearch, username).toList()
        return ldapUserDetailsMapper.mapUserFromContext(userFromSearch, username, authorities)
    }

}

inject bean in Application:

@Override
    Closure doWithSpring() {
        { ->
                userDetailsService(LdapUserDetailsManagerImpl)
        }
    }

or in resources.groovy

amsakni commented 4 years ago

It is indeed a grails issue, as I understand it: GormUserDetailsManager instance is by default injected even if you are using LDAP. Injecting GrailsLdapUserDetailsManager instead doesn't work because LDAP configuration isn't injected correctly.

dbaylerg commented 4 years ago

Thank you I will try the work around

vannakdy commented 1 year ago

http://localhost:8085/oauth/access_token?grant_type=refresh_token&refresh_token={your_acces_token} method : post

dbaylerg commented 1 year ago

@amsakni Apologies for the considerable time lapse but thank you for the fix. It was implemented and is working.