Search code examples
javaspring-securityspring-bootldapspring-ldap

Spring Security LDAP authentication user must be a member of an AD group


I've configured the Spring Boot Security as per: https://spring.io/guides/gs/securing-web/

I am able to login using my credentials perfectly. However, I need to add a checking that the AD user must also belong to a specific AD group (ie. AD-this-is-a-specific-group). On login, if the user does not belong to the specific AD group, then it should return a login error.

I've been searching for hours now and cannot seem to find a clear way to do this in the WebSecurityConfigurerAdapter , am I using the auth.groupSearchFilter correctly?

Here is my code:

@Configuration 
@EnableWebSecurity    
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
Environment env;

public LdapContextSource contextSource () {
    LdapContextSource contextSource= new LdapContextSource();

    contextSource.setUrl(env.getRequiredProperty("ldap.url"));
    contextSource.setBase(env.getRequiredProperty("ldap.baseDn"));
    contextSource.setUserDn(env.getRequiredProperty("ldap.bindDn"));
    contextSource.setPassword(env.getRequiredProperty("ldap.batchPassword"));
    contextSource.afterPropertiesSet();
    return contextSource;
}

@Override
protected void configure(AuthenticationManagerBuilder auth)
        throws Exception {
     auth.ldapAuthentication()
        .userSearchFilter("(cn={0})")           
        .groupSearchBase("OU=Account Groups,OU=ITS Security")
        .groupSearchFilter("(cn=AD-this-is-a-specific-group)") 
        .contextSource(contextSource()); 
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().anyRequest().fullyAuthenticated()
        .and()
        .formLogin();
}

Solution

  • Not sure if this is the best way to do this (in terms of Spring Security's lifecycle), but basically I provided my own DefaultLdapAuthoritiesPopulator, where I only override the getGroupMembershipRoles.

    First thing though, I have wrong auth.groupSearchFilter above, it should be:

        .groupSearchFilter("(member={0})") 
    

    Second, I've created an anonymous class with overridden method (that calls the super and checks for a the membership in the list of roles):

    auth
            .ldapAuthentication()
            .ldapAuthoritiesPopulator(new DefaultLdapAuthoritiesPopulator(contextSource, "OU=Account Groups,OU=ITS Security") {
    
                @Override
                public Set<GrantedAuthority> getGroupMembershipRoles(String userDn, String username) {
                    Set<GrantedAuthority> groupMembershipRoles = super.getGroupMembershipRoles(userDn, username);
    
                    boolean isMemberOfSpecificAdGroup = false;
                    for (GrantedAuthority grantedAuthority : groupMembershipRoles) {
    
                        if ("ROLE_AD-this-is-a-specific-group".equals(grantedAuthority.toString())) {                                                       
                            isMemberOfSpecificAdGroup = true;
                            break;
                        }
                    }
    
                    if (!isMemberOfSpecificAdGroup ) {
    
                        throw new BadCredentialsException("User must be a member of " + "AD-this-is-a-specific-group");
                    }
                    return groupMembershipRoles;
                }
            })
            .userSearchFilter("(cn={0})")           
            .groupSearchBase("OU=Account Groups,OU=ITS Security")
            .groupSearchFilter("(member={0})") 
            .contextSource(contextSource);