package qa.qcri.aidr.data.social.security;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import org.apache.log4j.Logger;
import org.socialsignin.springsocial.security.api.SpringSocialProfile;
import org.socialsignin.springsocial.security.signin.SpringSocialSecurityAuthenticationFactory;
import org.socialsignin.springsocial.security.signup.SignUpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
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.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.social.connect.Connection;
import org.springframework.social.connect.ConnectionRepository;
import org.springframework.social.connect.UsersConnectionRepository;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.util.MultiValueMap;
import qa.qcri.aidr.data.persistence.entity.UserAccount;
import qa.qcri.aidr.data.persistence.entity.UserConnection;
import qa.qcri.aidr.data.service.UserConnectionService;
import qa.qcri.aidr.data.service.UserService;
import qa.qcri.aidr.data.util.ConstantUtils;
import qa.qcri.aidr.data.util.RoleType;
@Repository
@Service
@Qualifier("springSocialUserDetailsService")
public class SpringSocialUserDetailService implements UserDetailsService {
private static Logger logger = Logger.getLogger(SpringSocialUserDetailService.class);
@Autowired
private UsersConnectionRepository usersConnectionRepository;
@Autowired
private SpringSocialSecurityAuthenticationFactory authenticationFactory;
@Autowired
private UserConnectionService userConnectionService;
@Autowired
private SignUpService<?> signUpService;
@Resource(name="userService")
private UserService userService;
@Override
public UserDetails loadUserByUsername(String combinedUserName)throws UsernameNotFoundException {
String provider = combinedUserName.substring(0, combinedUserName.indexOf(ConstantUtils.USER_NAME_SPLITTER));
String userName = combinedUserName.substring(combinedUserName.indexOf(ConstantUtils.USER_NAME_SPLITTER)+1);
ConnectionRepository connectionRepository = usersConnectionRepository.createConnectionRepository(userName);
SpringSocialProfile springSocialProfile = null;
try{
springSocialProfile = signUpService.getUserProfile(userName);
}catch(Exception e){
logger.error("Multiple accounts exist with same userName: "+userName,e);
}
List<Connection<?>> allConnections = getConnections(connectionRepository);
if (allConnections.size() > 0) {
Authentication authentication = null;
if(springSocialProfile == null){
UserConnection userProfile = userConnectionService.getByProviderIdAndUserId(provider, userName);
authentication = authenticationFactory.createAuthenticationForAllConnections(combinedUserName,
userProfile.getAccessToken(),allConnections);
}else{
authentication = authenticationFactory.createAuthenticationForAllConnections(combinedUserName,
springSocialProfile.getPassword(),allConnections);
}
UserAccount user = userService.fetchByUserName(combinedUserName);
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.addAll(authentication.getAuthorities());
List<RoleType> roles = userService.getUserRoles(user.getId());
if(roles != null && !roles.isEmpty() ){
for(RoleType role : roles){
GrantedAuthority authority = new SimpleGrantedAuthority(role.name());
authorities.add(authority);
}
}
return new User(combinedUserName, authentication.getCredentials().toString(), true, true, true, true,authorities);
} else {
logger.info("UsernameNotFoundException for user: "+combinedUserName);
throw new UsernameNotFoundException(combinedUserName);
}
}
private List<Connection<?>> getConnections(ConnectionRepository connectionRepository) {
MultiValueMap<String, Connection<?>> connections = connectionRepository.findAllConnections();
List<Connection<?>> allConnections = new ArrayList<Connection<?>>();
if (connections.size() > 0) {
for (List<Connection<?>> connectionList : connections.values()) {
for (Connection<?> connection : connectionList) {
allConnections.add(connection);
}
}
}
return allConnections;
}
}