问题
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
回答1:
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
.
回答2:
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.
来源:https://stackoverflow.com/questions/27480354/spring-security-how-to-map-active-directory-users-to-application-users