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 }