· 7 years ago · Jan 24, 2018, 04:52 PM
1package com.mycompany.myapp.service;
2
3import com.mycompany.myapp.domain.Authority;
4import com.mycompany.myapp.domain.User;
5import com.mycompany.myapp.repository.AuthorityRepository;
6import com.mycompany.myapp.repository.UserRepository;
7import com.mycompany.myapp.security.AuthoritiesConstants;
8import org.apache.commons.lang3.RandomStringUtils;
9import org.apache.commons.lang3.StringUtils;
10import org.slf4j.Logger;
11import org.slf4j.LoggerFactory;
12import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
13import org.springframework.security.core.Authentication;
14import org.springframework.security.core.context.SecurityContextHolder;
15import org.springframework.security.core.userdetails.UserDetails;
16import org.springframework.security.core.userdetails.UserDetailsService;
17import org.springframework.security.crypto.password.PasswordEncoder;
18import org.springframework.social.connect.*;
19import org.springframework.social.facebook.connect.FacebookConnectionFactory;
20import org.springframework.social.google.connect.GoogleConnectionFactory;
21import org.springframework.social.oauth1.OAuthToken;
22import org.springframework.social.oauth2.AccessGrant;
23import org.springframework.social.twitter.connect.TwitterConnectionFactory;
24import org.springframework.stereotype.Service;
25
26import java.util.*;
27
28@Service
29public class SocialService {
30
31 private final Logger log = LoggerFactory.getLogger(SocialService.class);
32
33 private final UsersConnectionRepository usersConnectionRepository;
34
35 private final AuthorityRepository authorityRepository;
36
37 private final PasswordEncoder passwordEncoder;
38
39 private final UserRepository userRepository;
40
41 private final UserDetailsService userDetailsService;
42
43 private final ConnectionFactoryLocator connectionFactoryLocator;
44
45 private final MailService mailService;
46
47 public SocialService(UsersConnectionRepository usersConnectionRepository, AuthorityRepository authorityRepository,
48 PasswordEncoder passwordEncoder, UserRepository userRepository, UserDetailsService userDetailsService, ConnectionFactoryLocator connectionFactoryLocator, MailService mailService) {
49
50 this.usersConnectionRepository = usersConnectionRepository;
51 this.authorityRepository = authorityRepository;
52 this.passwordEncoder = passwordEncoder;
53 this.userRepository = userRepository;
54 this.userDetailsService = userDetailsService;
55 this.connectionFactoryLocator = connectionFactoryLocator;
56 this.mailService = mailService;
57 }
58
59 public void deleteUserSocialConnection(String login) {
60 ConnectionRepository connectionRepository = usersConnectionRepository.createConnectionRepository(login);
61 connectionRepository.findAllConnections().keySet().stream()
62 .forEach(providerId -> {
63 connectionRepository.removeConnections(providerId);
64 log.debug("Delete user social connection providerId: {}", providerId);
65 });
66 }
67
68 public User createSocialUser(Connection<?> connection, String langKey) {
69 if (connection == null) {
70 log.error("Cannot create social user because connection is null");
71 throw new IllegalArgumentException("Connection cannot be null");
72 }
73 UserProfile userProfile = connection.fetchUserProfile();
74 String providerId = connection.getKey().getProviderId();
75 String imageUrl = connection.getImageUrl();
76 User user = createUserIfNotExist(userProfile, langKey, providerId, imageUrl);
77 createSocialConnection(user.getLogin(), connection);
78 mailService.sendSocialRegistrationValidationEmail(user, providerId);
79 return user;
80 }
81
82 private User createUserIfNotExist(UserProfile userProfile, String langKey, String providerId, String imageUrl) {
83 String email = userProfile.getEmail();
84 String userName = userProfile.getUsername();
85 if (!StringUtils.isBlank(userName)) {
86 userName = userName.toLowerCase(Locale.ENGLISH);
87 }
88 if (StringUtils.isBlank(email) && StringUtils.isBlank(userName)) {
89 log.error("Cannot create social user because email and login are null");
90 throw new IllegalArgumentException("Email and login cannot be null");
91 }
92 if (StringUtils.isBlank(email) && userRepository.findOneByLogin(userName).isPresent()) {
93 log.error("Cannot create social user because email is null and login already exist, login -> {}", userName);
94 throw new IllegalArgumentException("Email cannot be null with an existing login");
95 }
96 if (!StringUtils.isBlank(email)) {
97 Optional<User> user = userRepository.findOneByEmailIgnoreCase(email);
98 if (user.isPresent()) {
99 log.info("User already exist associate the connection to this account");
100 return user.get();
101 }
102 }
103
104 String login = getLoginDependingOnProviderId(userProfile, providerId);
105 String encryptedPassword = passwordEncoder.encode(RandomStringUtils.random(10));
106 Set<Authority> authorities = new HashSet<>(1);
107 authorities.add(authorityRepository.findOne(AuthoritiesConstants.USER));
108
109 User newUser = new User();
110 newUser.setLogin(login);
111 newUser.setPassword(encryptedPassword);
112 newUser.setFirstName(userProfile.getFirstName());
113 newUser.setLastName(userProfile.getLastName());
114 newUser.setEmail(email);
115 newUser.setActivated(true);
116 newUser.setAuthorities(authorities);
117 newUser.setLangKey(langKey);
118 newUser.setImageUrl(imageUrl);
119
120 return userRepository.save(newUser);
121 }
122
123 /**
124 * @return login if provider manage a login like Twitter or GitHub otherwise email address.
125 * Because provider like Google or Facebook didn't provide login or login like "12099388847393"
126 */
127 public String getLoginDependingOnProviderId(UserProfile userProfile, String providerId) {
128 switch (providerId) {
129 case "twitter":
130 return userProfile.getUsername().toLowerCase();
131 default:
132 return userProfile.getFirstName().toLowerCase() + "_" + userProfile.getLastName().toLowerCase();
133 }
134 }
135
136 private void createSocialConnection(String login, Connection<?> connection) {
137 ConnectionRepository connectionRepository = usersConnectionRepository.createConnectionRepository(login);
138 connectionRepository.addConnection(connection);
139 }
140
141 public void loadConnectionFromToken(String token, String secret, String provider) {
142 Connection connection = null;
143 UserProfile userProfile = null;
144 if ("facebook".equals(provider)) {
145 AccessGrant accessGrant = new AccessGrant(token);
146 connection = ((FacebookConnectionFactory)connectionFactoryLocator.getConnectionFactory(provider)).createConnection(accessGrant);
147 userProfile = connection.fetchUserProfile();
148 } else if ("twitter".equals(provider)) {
149 OAuthToken oAuthToken = new OAuthToken(token, secret);
150 connection = ((TwitterConnectionFactory)connectionFactoryLocator.getConnectionFactory("twitter")).createConnection(oAuthToken);
151 userProfile = connection.fetchUserProfile();
152 } else if ("google".equals(provider)) {
153 AccessGrant accessGrant = new AccessGrant(token);
154 connection = ((GoogleConnectionFactory)connectionFactoryLocator.getConnectionFactory(provider)).createConnection(accessGrant);
155 userProfile = connection.fetchUserProfile();
156 }
157
158 // check if the user exists
159 List<String> userIds = usersConnectionRepository.findUserIdsWithConnection(connection);
160 String userLogin;
161 if (userIds.size() == 0) {
162 log.debug("User needs to be created");
163 userLogin = createSocialUser(connection, "en").getLogin();
164 } else {
165 log.debug("User already exists, logging in");
166 userLogin = getLoginDependingOnProviderId(userProfile, provider);
167 }
168 UserDetails user = userDetailsService.loadUserByUsername(userLogin);
169 Authentication newAuth = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
170 SecurityContextHolder.getContext().setAuthentication(newAuth);
171 }
172}