package com.danielbohry.authservice.service.auth; import com.danielbohry.authservice.api.dto.AuthenticationRequest; import com.danielbohry.authservice.api.dto.AuthenticationResponse; import com.danielbohry.authservice.client.MailClient; import com.danielbohry.authservice.domain.ApplicationUser; import com.danielbohry.authservice.service.user.UserService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; 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.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import static com.danielbohry.authservice.service.auth.UserConverter.convert; import static java.time.Instant.now; @Slf4j @Service @RequiredArgsConstructor public class AuthService implements UserDetailsService { private final UserService service; private final JwtService jwtService; private final AuthenticationManager authenticationManager; private final PasswordEncoder passwordEncoder; private final MailClient mailClient; @Value("${host.name:localhost}") private String host; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { var user = service.findByUsername(username); var authorities = user.getRoles().stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role)).toList(); return new User(user.getUsername(), user.getPassword(), authorities); } public AuthenticationResponse register(AuthenticationRequest request) { UserDetails user = buildUserDetails(request); ApplicationUser toSave = convert(user, request.getEmail()); toSave.setCreatedAt(now()); toSave.setUpdatedAt(now()); toSave.setLastLoginAt(now()); ApplicationUser saved = service.create(toSave); Authentication authentication = jwtService.generateToken(saved); log.info("Username [{}] registered", request.getUsername()); return buildResponse(saved, authentication); } public AuthenticationResponse authenticate(AuthenticationRequest request) { authenticationManager.authenticate(new UsernamePasswordAuthenticationToken( request.getUsername(), request.getPassword()) ); ApplicationUser user = service.findByUsername(request.getUsername()); Authentication authentication = jwtService.generateToken(user); log.info("Username [{}] authenticated", request.getUsername()); user.setLastLoginAt(now()); service.update(user.getId(), user); return buildResponse(user, authentication); } public AuthenticationResponse refresh(ApplicationUser applicationUser) { if (!applicationUser.isActive()) { return null; } ApplicationUser user = service.findByUsername(applicationUser.getUsername()); Authentication authentication = jwtService.generateToken(user); user.setLastLoginAt(now()); service.update(user.getId(), user); return buildResponse(user, authentication); } public AuthenticationResponse changePassword(String userId, String currentPassword, String newPassword) { ApplicationUser user = service.changePassword(userId, currentPassword, newPassword, passwordEncoder); Authentication authentication = jwtService.generateToken(user); return buildResponse(user, authentication); } public AuthenticationResponse resetPassword(String userId, String newPassword) { ApplicationUser user = service.resetPassword(userId, newPassword, passwordEncoder); Authentication authentication = jwtService.generateToken(user); return buildResponse(user, authentication); } public AuthenticationResponse updateProfile(String userId, String currentPassword, String newPassword, String email) { ApplicationUser user = service.updateProfile(userId, currentPassword, newPassword, email, passwordEncoder); Authentication authentication = jwtService.generateToken(user); return buildResponse(user, authentication); } public void sendResetPasswordEmail(String username) { try { ApplicationUser user = service.findByUsername(username); Authentication systemAuth = jwtService.generateSystemToken(); Authentication userAuth = jwtService.generateToken(user, 10); if (user.getEmail() != null && !user.getEmail().isEmpty()) { String resetUrl = host + "/?reset-password&token=" + userAuth.token(); String emailContent = buildContent(user.getUsername(), resetUrl); mailClient.sendMail(user.getEmail(), "Password Reset Request - Auth Service", emailContent, "Bearer " + systemAuth.token()); } } catch (Exception ignored) { } } private UserDetails buildUserDetails(AuthenticationRequest request) { return User.builder() .username(request.getUsername()) .password(passwordEncoder.encode(request.getPassword())) .build(); } private static AuthenticationResponse buildResponse(ApplicationUser user, Authentication authentication) { return AuthenticationResponse.builder() .id(user.getId()) .username(authentication.username()) .email(user.getEmail()) .token(authentication.token()) .expirationDate(authentication.expirationDate()) .roles(authentication.authorities()) .build(); } private String buildContent(String username, String resetUrl) { return String.format(""" Hello %s, You requested a password reset for your account. Click here to reset your password: %s This link expires in 10 minutes. If you didn't request this, please ignore this email. Auth Service Team """, username, resetUrl); } }