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.pac4j.springframework.security.authentication.ClientAuthenticationToken; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.core.userdetails.AuthenticationUserDetailsService; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; import javax.inject.Inject; /** * */ @Component public class GoogleAutoRegisteringUserDetailsService implements AuthenticationUserDetailsService<ClientAuthenticationToken> { private final Logger log = LoggerFactory.getLogger(GoogleAutoRegisteringUserDetailsService.class); private static final String EMAIL_ATTRIBUTE = "email"; private static final String FIRSTNAME_ATTRIBUTE = "given_name"; private static final String LASTNAME_ATTRIBUTE = "family_name"; private static final String FULLNAME_ATTRIBUTE = "name"; @Inject private UserService userService; @Inject private DomainRepository domainRepository; @Inject private TatamiUserDetailsService userDetailsService; // => handles grantedAuthorities @Override public UserDetails loadUserDetails(ClientAuthenticationToken token) throws UsernameNotFoundException { String login = getAttributeValue(token, EMAIL_ATTRIBUTE); if (login == null) { String msg = "OAuth response did not contain the user email"; log.error(msg); throw new UsernameNotFoundException(msg); } if (!login.contains("@")) { log.debug("User login {} from OAuth response is incorrect.", login); throw new UsernameNotFoundException("OAuth response did not contains a valid user email"); } // Automatically create OpenId users in Tatami : UserDetails userDetails; try { userDetails = userDetailsService.loadUserByUsername(login); // ensure that this user has access to its domain if it has been created before domainRepository.updateUserInDomain(DomainUtil.getDomainFromLogin(login), login); } catch (UsernameNotFoundException e) { log.info("User with login : \"{}\" doesn't exist yet in Tatami database - creating it...", login); userDetails = getNewlyCreatedUserDetails(token); } return userDetails; } private org.springframework.security.core.userdetails.User getNewlyCreatedUserDetails(ClientAuthenticationToken token) { String login = getAttributeValue(token, EMAIL_ATTRIBUTE); String firstName = getAttributeValue(token, FIRSTNAME_ATTRIBUTE); String lastName = getAttributeValue(token, LASTNAME_ATTRIBUTE); String fullName = getAttributeValue(token, FULLNAME_ATTRIBUTE); if (firstName == null && lastName == null) { // if we haven't first nor last name, we use fullName as last name to begin with : lastName = fullName; } User user = new User(); // Note : The email could change... and the OpenId not // moreover an OpenId account could potentially be associated with several email addresses // so we store it for future use case : user.setLogin(login); user.setFirstName(firstName); user.setLastName(lastName); log.debug("User: {}", user); userService.createUser(user); return userDetailsService.getTatamiUserDetails(login, user.getPassword()); } private String getAttributeValue(ClientAuthenticationToken token, String name) { return (String) token.getUserProfile().getAttributes().get(name); } }