2

I'm integrating Active Directory authentication in an existing Spring web app.

At the moment user details are stored in a DB table and I implemented a custom UserDetailsService to authenticate users.

Following several tutorials I implemented Active Directory support via ActiveDirectoryLdapAuthenticationProvider in my application, and it basically works, but I need something more specific.

Instead of mapping AD groups to application roles, I need to map AD users to existing users in my web app. In other words I want to enable AD authentication only for users in my Users table. A user can access via AD credentials ONLY IF is already registered in application DB.

Authorization info for each user are stored in DB. This way, each user can be authenticated both via DB user+password or via AD.

Is it possible to achieve this with Spring Security? and how?

NOTE I'm using Spring v 3.2.9 and Spring Security v 3.2.3

davioooh
  • 23,742
  • 39
  • 159
  • 250

2 Answers2

3

As a workaround I implementend a custom AuthenticationProvider and a custom UserDetailsContextMapper.

Becouse ActiveDirectoryLdapAuthenticationProvider is a final class I implemented the ADCustomAuthenticationProvider via composition, this way:

public class ADCustomAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private ActiveDirectoryLdapAuthenticationProvider adAuthProvider;
    @Autowired
    private UserDao uDao;

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public Authentication authenticate(Authentication authentication)
            throws AuthenticationException {
        String principal = authentication.getPrincipal().toString();
        String username = principal.split("@")[0];
        User utente = uDao.findByUsername(username);
        if (utente == null) {
            throw new ADUnregisteredUserAuthenticationException("user ["
                    + principal + "] is not registered");
        }
        return adAuthProvider.authenticate(authentication);
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return adAuthProvider.supports(authentication);
    }

}

In the mapper I extended LdapUserDetailsMapper implementing only mapUserFromContext method.

public class ADCustomUserDetailsContextMapper extends LdapUserDetailsMapper {

    @Autowired
    private UserDetailsService userDetailsService; // ... the service used for DB authentication

    @Override
    public UserDetails mapUserFromContext(DirContextOperations ctx,
            String username, Collection<? extends GrantedAuthority> authorities) {
        return userDetailsService.loadUserByUsername(username);
    }
}

(I'll probably need to implement mapUserToContext method beacuse I'm using a custom UserDetails implementation that not extends LdapUserDetails, so the reverse convertion process could throw an exception...)

NOTE This way I'm repeating the same query (to Users table) two times... I'd like to find a way to make a single query and share the result among AuthenticationProvider and UserDetailsContextMapper.e result among AuthenticationProvider and UserDetailsContextMapper.

davioooh
  • 23,742
  • 39
  • 159
  • 250
0

If the user is not the user database, it should be assigned "no access" in the authorization process. So it doesn't really matter if he's authenticated or not, the application won't allow him to access because he's not authorized to the application.

Cuball
  • 89
  • 5