package fr.ippon.tatami.security; import fr.ippon.tatami.domain.User; import fr.ippon.tatami.repository.DomainRepository; import fr.ippon.tatami.service.UserService; import fr.ippon.tatami.service.util.DomainUtil; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.InternalAuthenticationServiceException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.ldap.authentication.LdapAuthenticationProvider; import org.springframework.security.ldap.authentication.LdapAuthenticator; import javax.inject.Inject; /** * Tatami specific LdapAuthenticationProvider. * * @author Julien Dubois */ public class TatamiLdapAuthenticationProvider extends LdapAuthenticationProvider { private final Logger log = LoggerFactory.getLogger(TatamiLdapAuthenticationProvider.class); @Inject private UserService userService; @Inject private DomainRepository domainRepository; @Inject private TatamiUserDetailsService userDetailsService; // => handles grantedAuthorities /** * The domain on which this provider is suitable to authenticate user */ private String managedDomain; public TatamiLdapAuthenticationProvider(LdapAuthenticator authenticator, String managedDomain) { super(authenticator); if (StringUtils.isEmpty(managedDomain)) { throw new IllegalArgumentException("You must provide a managedDomain on this TatamiLdapAuthenticationProvider"); } this.managedDomain = managedDomain; } private boolean canHandleAuthentication(Authentication authentication) { String login = authentication.getName(); if (!login.contains("@")) { log.debug("User login {} is incorrect.", login); throw new BadCredentialsException(messages.getMessage( "LdapAuthenticationProvider.badCredentials", "Bad credentials")); } String domain = DomainUtil.getDomainFromLogin(login); return domain.equalsIgnoreCase(managedDomain); } @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { if (!canHandleAuthentication(authentication)) { return null; // this provider is not suitable for this domain } log.debug("Authenticating {} with LDAP", authentication.getName()); String login = authentication.getName().toLowerCase(); String username = DomainUtil.getUsernameFromLogin(login); // Use temporary token to use username, and not login to authenticate on ldap : UsernamePasswordAuthenticationToken tmpAuthentication = new UsernamePasswordAuthenticationToken(username, authentication.getCredentials(), null); try { super.authenticate(tmpAuthentication); } catch (InternalAuthenticationServiceException iase) { // Without this : there is no log when the ldap server or the ldap configuration is broken : log.error("Internal Error while authenticating " + authentication.getName() + " with LDAP", iase); throw iase; } //Automatically create LDAP users in Tatami User user = userService.getUserByLogin(login); if (user == null) { user = new User(); user.setLogin(login); userService.createUser(user); } else { // ensure that this user has access to its domain if it has been created before domainRepository.updateUserInDomain(user.getDomain(), user.getLogin()); } // The real authentication object uses the login, and not the username org.springframework.security.core.userdetails.User realUser = userDetailsService.getTatamiUserDetails(login, authentication.getCredentials().toString()); return new UsernamePasswordAuthenticationToken(realUser, authentication.getCredentials(), realUser.getAuthorities()); } }