Spring Security with LDAP and Database roles

Jon Smith picture Jon Smith · May 22, 2013 · Viewed 8.5k times · Source

In our new insurance project, I am trying to implement with Ldap .

I want to just check username/password against AD, once user found in AD. I want to authorize him from user table(app authorized users) with access levels in database. Could someone give sample/point me for a good resource.

Answer

pfac picture pfac · Jan 21, 2015

The easiest way to achieve this now (Spring Security 3.2.5.RELEASE) is by implementing a custom LdapAuthoritiesPopulator which uses a custom JdbcDaoImpl to obtain the authorities from the database.

Code

Assuming you are using the default database schema, and that you are using the same username for authentication in LDAP and as the foreign key in the authorities table, you only need this:

package demo;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;

import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl;

import org.springframework.ldap.core.DirContextOperations;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;

/*
 * You need to extend JdbcDaoImpl to expose the protected method loadUserAuthorities.
 */
public class CustomJdbcUserDetailsService extends JdbcDaoImpl {

    @Override
    public List<GrantedAuthority> loadUserAuthorities(String username) {
        return super.loadUserAuthorities(username);
    }
}


/*
 * Then, the only thing your populator needs to do is use the custom UserDetailsService above.
 */
public class CustomLdapAuthoritiesPopulator implements LdapAuthoritiesPopulator {

    private static final Logger LOGGER = LoggerFactory.getLogger(CustomLdapAuthoritiesPopulator.class);

    private CustomJdbcUserDetailsService service;

    public CustomLdapAuthoritiesPopulator(CustomJdbcUserDetailsService service) {
        this.service = service;
    }

    public Collection<? extends GrantedAuthority> getGrantedAuthorities(DirContextOperations user, String username) {
        return service.loadUserAuthorities(username);
    }

}

The only thing left now is configure the LDAP authentication provider to use CustomLdapAuthoritiesPopulator.

Java Config

In a @Configuration annotated subclass of GlobalMethodSecurityConfiguration or WebSecurityConfigurerAdapter (depending on your case), add the following:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {

    /* other authentication configurations you might have */

    /*
     * This assumes that the dataSource configuring
     * the connection to the database has been Autowired
     * into this bean.
     *
     * Adapt according to your specific case.
     */
    CustomJdbcUserDetailsService customJdbcUserDetailsService = new CustomJdbcUserDetailsService();
    customJdbcUserDetailsService.setDataSource(dataSource);

    CustomLdapAuthoritiesPopulator customLdapAuthoritiesPopulator = new CustomLdapAuthoritiesPopulator(customJdbcUserDetailsService);

    auth.ldapAuthentication().ldapAuthoritiesPopulator(customLdapAuthoritiesPopulator)/* other LDAP configurations you might have */;

    /* yet more authentication configurations you might have */
}

Refer to https://github.com/pfac/howto-spring-security for a working example.

XML Config

Disclaimer: I've been working solely with Java configuration, so tread cautiously, there might be some errors.

Unlike other configurations for authenticating with LDAP, there seems to be no pretty XML tags to customize the LdapAuthoritiesPopulator. So, it has to be done manually. Assuming a bean contextSource configuring the connection to the LDAP server has been defined, add the following to your Spring XML configuration:

<beans:bean id="customJdbcUserDetailsService" class="demo.CustomJdbcUserDetailsService" />
<beans:bean id="customLdapAuthoritiesPopulator" class="demo.CustomLdapAuthoritiesPopulator">
    <beans:constructor-arg ref="customJdbcUserDetailsService" />
</beans:bean>

<beans:bean id="ldapAuthProvider" class="org.springframework.security.ldap.authentication.LdapAuthenticationProvider">
    <beans:constructor-arg>
        <beans:bean class="org.springframework.security.ldap.authentication.BindAuthenticator">
            <beans:constructor-arg ref="contextSource" />
            <!--
                other configurations you might need
            -->
        </beans:bean>
    </beans:constructor-arg>
    <beans:constructor-arg ref="customLdapAuthoritiesPopulator" />
</beans:bean>

<security:authentication-manager>
  <security:authentication-provider ref="ldapAuthProvider" />
</security:authentication-manager>

Source: http://spapas.github.io/2013/10/14/spring-ldap-custom-authorities/#spring-security-ldap-with-custom-authorities