View Javadoc
1   package org.petify.backend.services;
2   
3   import org.petify.backend.models.ApplicationUser;
4   import org.petify.backend.models.OAuth2Provider;
5   import org.petify.backend.models.Role;
6   import org.petify.backend.repository.OAuth2ProviderRepository;
7   import org.petify.backend.repository.RoleRepository;
8   import org.petify.backend.repository.UserRepository;
9   
10  import org.springframework.security.core.authority.SimpleGrantedAuthority;
11  import org.springframework.security.crypto.password.PasswordEncoder;
12  import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService;
13  import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
14  import org.springframework.security.oauth2.core.OAuth2AuthenticationException;
15  import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
16  import org.springframework.security.oauth2.core.user.OAuth2User;
17  import org.springframework.stereotype.Service;
18  import org.springframework.transaction.annotation.Transactional;
19  
20  import java.util.ArrayList;
21  import java.util.Collection;
22  import java.util.HashMap;
23  import java.util.HashSet;
24  import java.util.Map;
25  import java.util.Optional;
26  import java.util.Set;
27  import java.util.UUID;
28  
29  @Service
30  public class CustomOAuth2UserService extends DefaultOAuth2UserService {
31  
32      private final UserRepository userRepository;
33      private final RoleRepository roleRepository;
34      private final OAuth2ProviderRepository oauth2ProviderRepository;
35      private final PasswordEncoder passwordEncoder;
36      private final AchievementService achievementService;
37  
38      public CustomOAuth2UserService(
39              UserRepository userRepository,
40              RoleRepository roleRepository,
41              OAuth2ProviderRepository oauth2ProviderRepository,
42              PasswordEncoder passwordEncoder,
43              AchievementService achievementService) {
44          this.userRepository = userRepository;
45          this.roleRepository = roleRepository;
46          this.oauth2ProviderRepository = oauth2ProviderRepository;
47          this.passwordEncoder = passwordEncoder;
48          this.achievementService = achievementService;
49      }
50  
51      @Override
52      @Transactional
53      public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
54          OAuth2User oauth2User = super.loadUser(userRequest);
55  
56          String providerId = userRequest.getClientRegistration().getRegistrationId();
57          String providerUserId = oauth2User.getAttribute("sub");
58  
59          String email = oauth2User.getAttribute("email");
60          String name = oauth2User.getAttribute("name");
61  
62          Optional<OAuth2Provider> existingProvider =
63                  oauth2ProviderRepository.findByProviderIdAndProviderUserId(providerId, providerUserId);
64  
65          ApplicationUser user;
66  
67          if (existingProvider.isPresent()) {
68              user = existingProvider.get().getUser();
69  
70              existingProvider.get().setEmail(email);
71              existingProvider.get().setName(name);
72              oauth2ProviderRepository.save(existingProvider.get());
73          } else {
74              String username = (email != null) ? email : name + "_" + UUID.randomUUID().toString().substring(0, 8);
75  
76              Optional<ApplicationUser> existingUser = userRepository.findByUsername(username);
77  
78              if (existingUser.isPresent()) {
79                  user = existingUser.get();
80              } else {
81                  Role userRole = roleRepository.findByAuthority("USER")
82                          .orElseThrow(() -> new RuntimeException("USER role not found"));
83  
84                  Set<Role> authorities = new HashSet<>();
85                  authorities.add(userRole);
86  
87                  user = new ApplicationUser();
88                  user.setUsername(username);
89                  user.setEmail(email);
90  
91                  if (name != null) {
92                      String[] nameParts = name.split(" ", 2);
93                      user.setFirstName(nameParts[0]);
94                      if (nameParts.length > 1) {
95                          user.setLastName(nameParts[1]);
96                      }
97                  }
98  
99                  user.setPassword(passwordEncoder.encode(UUID.randomUUID().toString()));
100                 user.setAuthorities(authorities);
101 
102                 user = userRepository.save(user);
103 
104                 achievementService.initializeUserAchievements(user);
105 
106                 OAuth2Provider provider = new OAuth2Provider(
107                         providerId,
108                         providerUserId,
109                         user,
110                         email,
111                         name
112                 );
113                 oauth2ProviderRepository.save(provider);
114             }
115         }
116 
117         Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
118         user.getAuthorities().forEach(role -> {
119             String authority = role.getAuthority();
120             if (!authority.startsWith("ROLE_")) {
121                 authority = "ROLE_" + authority;
122             }
123             authorities.add(new SimpleGrantedAuthority(authority));
124         });
125 
126         Map<String, Object> attributes = new HashMap<>(oauth2User.getAttributes());
127         attributes.put("userId", user.getUserId());
128 
129         return new DefaultOAuth2User(
130                 authorities,
131                 attributes,
132                 "email"
133         );
134     }
135 }