In our new insurance project, I am trying to implement spring-security with Ldap active-directory.
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.
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.
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
.
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.
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>