package com.faf223.expensetrackerfaf.service; import com.faf223.expensetrackerfaf.config.JwtService; import com.faf223.expensetrackerfaf.controller.auth.AuthenticationRequest; import com.faf223.expensetrackerfaf.controller.auth.AuthenticationResponse; import com.faf223.expensetrackerfaf.controller.auth.RegisterRequest; import com.faf223.expensetrackerfaf.controller.auth.TokenRefreshRequest; import com.faf223.expensetrackerfaf.model.Credential; import com.faf223.expensetrackerfaf.model.User; import com.faf223.expensetrackerfaf.repository.CredentialRepository; import com.faf223.expensetrackerfaf.repository.UserRepository; import com.faf223.expensetrackerfaf.security.PersonDetails; import com.faf223.expensetrackerfaf.util.exceptions.UserNotAuthenticatedException; import com.faf223.expensetrackerfaf.util.exceptions.UserNotFoundException; import lombok.RequiredArgsConstructor; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.core.user.OAuth2User; import org.springframework.stereotype.Service; import java.util.Optional; @Service @RequiredArgsConstructor public class AuthenticationService { private final UserRepository userRepository; private final UserService userService; private final CredentialRepository credentialRepository; private final PasswordEncoder passwordEncoder; private final JwtService jwtService; private final AuthenticationManager authenticationManager; private final PasswordGenerator passwordGenerator; public AuthenticationResponse register(RegisterRequest request) { User user = User.builder() .firstName(request.getFirstname()) .lastName(request.getLastname()) .username(request.getUsername()) .build(); userRepository.save(user); Credential credential = new Credential(user, request.getEmail(), passwordEncoder.encode(request.getPassword())); credentialRepository.save(credential); UserDetails userDetails = new PersonDetails(credential); String jwtToken = jwtService.generateToken(userDetails); String refreshToken = jwtService.generateRefreshToken(userDetails); return AuthenticationResponse.builder() .accessToken(jwtToken) .refreshToken(refreshToken) .build(); } public AuthenticationResponse register(OAuth2User oAuth2User) { String userEmail = oAuth2User.getAttribute("email"); // Check if the user is already registered Optional existingCredential = credentialRepository.findByEmail(userEmail); if (existingCredential.isPresent()) { UserDetails userDetails = new PersonDetails(existingCredential.get()); String jwtToken = jwtService.generateToken(userDetails); String refreshToken = jwtService.generateRefreshToken(userDetails); return AuthenticationResponse.builder() .accessToken(jwtToken) .refreshToken(refreshToken) .build(); } String givenName = oAuth2User.getAttribute("given_name"); String familyName = oAuth2User.getAttribute("family_name"); String email = oAuth2User.getAttribute("email"); User user = User.builder() .firstName(givenName) .lastName(familyName) .username(email) .build(); String randomPassword = passwordGenerator.generateRandomPassword(8); user.setPassword(passwordEncoder.encode(randomPassword)); userRepository.save(user); Credential credential = new Credential(user, email, passwordEncoder.encode(randomPassword)); credentialRepository.save(credential); UserDetails userDetails = new PersonDetails(credential); String jwtToken = jwtService.generateToken(userDetails); String refreshToken = jwtService.generateRefreshToken(userDetails); System.out.println("New user: " + user); System.out.println("New credentials: " + credential); return AuthenticationResponse.builder() .accessToken(jwtToken) .refreshToken(refreshToken) .build(); } public AuthenticationResponse authenticate(AuthenticationRequest request) { authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(request.getEmail(), request.getPassword())); Credential credential = credentialRepository.findByEmail(request.getEmail()).orElseThrow((() -> new UserNotFoundException("User not found"))); UserDetails userDetails = new PersonDetails(credential); String jwtToken = jwtService.generateToken(userDetails); String refreshToken = jwtService.generateRefreshToken(userDetails); return AuthenticationResponse.builder() .accessToken(jwtToken) .refreshToken(refreshToken) .build(); } public AuthenticationResponse refreshAccessToken(TokenRefreshRequest refreshRequest) { String refreshToken = refreshRequest.getRefreshToken(); Optional credential = credentialRepository.findByEmail(jwtService.extractUsername(refreshToken)); if (credential.isPresent()) { UserDetails userDetails = new PersonDetails(credential.get()); String jwtToken = jwtService.generateToken(userDetails); return AuthenticationResponse.builder() .accessToken(jwtToken) .refreshToken(refreshToken) .build(); } else { throw new UserNotAuthenticatedException("Invalid or expired refresh token"); } } public void updatePassword(String newPassword) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); if (authentication != null && authentication.getPrincipal() instanceof UserDetails userDetails) { User user = userService.getUserByEmail(userDetails.getUsername()); Optional credential = credentialRepository.findByUser(user); if (credential.isPresent()) { Credential updatedCredential = credential.get(); updatedCredential.setPassword(passwordEncoder.encode(newPassword)); credentialRepository.save(updatedCredential); } } else throw new UserNotFoundException("User not found!"); } }