add email verification after account registration
This commit is contained in:
@@ -6,6 +6,11 @@ import com.krrishg.dto.AuthResponse.UserInfo;
|
||||
import com.krrishg.dto.LoginRequest;
|
||||
import com.krrishg.dto.RefreshTokenRequest;
|
||||
import com.krrishg.dto.RegisterRequest;
|
||||
import com.krrishg.dto.RegistrationResponse;
|
||||
import com.krrishg.dto.ResendVerificationRequest;
|
||||
import com.krrishg.dto.SetPasswordRequest;
|
||||
import com.krrishg.dto.VerifyEmailRequest;
|
||||
import com.krrishg.dto.VerifyEmailResponse;
|
||||
import com.krrishg.service.AuthService;
|
||||
import com.krrishg.support.TestSecurityConfig;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
@@ -20,6 +25,7 @@ import org.springframework.test.web.servlet.MockMvc;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||
@@ -40,14 +46,9 @@ class AuthControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerReturns201() throws Exception {
|
||||
AuthResponse response = AuthResponse.builder()
|
||||
.accessToken("at-123")
|
||||
.refreshToken("rt-456")
|
||||
.tokenType("Bearer")
|
||||
.user(new UserInfo(UUID.randomUUID(), "test@example.com", "Test", null))
|
||||
.build();
|
||||
when(authService.register(any(RegisterRequest.class))).thenReturn(response);
|
||||
void registerReturns201WithMessage() throws Exception {
|
||||
when(authService.register(any(RegisterRequest.class)))
|
||||
.thenReturn(new RegistrationResponse("If this email is available, a verification link has been sent."));
|
||||
|
||||
RegisterRequest request = new RegisterRequest();
|
||||
request.setEmail("test@example.com");
|
||||
@@ -58,10 +59,7 @@ class AuthControllerTest {
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isCreated())
|
||||
.andExpect(jsonPath("$.accessToken").value("at-123"))
|
||||
.andExpect(jsonPath("$.refreshToken").value("rt-456"))
|
||||
.andExpect(jsonPath("$.tokenType").value("Bearer"))
|
||||
.andExpect(jsonPath("$.user.email").value("test@example.com"));
|
||||
.andExpect(jsonPath("$.message").value("If this email is available, a verification link has been sent."));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -112,6 +110,22 @@ class AuthControllerTest {
|
||||
.andExpect(jsonPath("$.detail").value("Invalid email or password"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void loginReturns400OnUnverifiedEmail() throws Exception {
|
||||
when(authService.login(any(LoginRequest.class)))
|
||||
.thenThrow(new IllegalArgumentException("Please verify your email address before logging in"));
|
||||
|
||||
LoginRequest request = new LoginRequest();
|
||||
request.setEmail("unverified@example.com");
|
||||
request.setPassword("password123");
|
||||
|
||||
mockMvc.perform(post("/api/auth/login")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(jsonPath("$.detail").value("Please verify your email address before logging in"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshReturns200() throws Exception {
|
||||
AuthResponse response = AuthResponse.builder()
|
||||
@@ -137,4 +151,93 @@ class AuthControllerTest {
|
||||
mockMvc.perform(post("/api/auth/logout"))
|
||||
.andExpect(status().isNoContent());
|
||||
}
|
||||
|
||||
@Test
|
||||
void verifyEmailReturns200() throws Exception {
|
||||
when(authService.verifyEmail(any(VerifyEmailRequest.class)))
|
||||
.thenReturn(new VerifyEmailResponse("Email verified successfully", "setup-token-123"));
|
||||
|
||||
VerifyEmailRequest request = new VerifyEmailRequest();
|
||||
request.setToken("valid-token");
|
||||
|
||||
mockMvc.perform(post("/api/auth/verify-email")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.message").value("Email verified successfully"))
|
||||
.andExpect(jsonPath("$.setupToken").value("setup-token-123"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void verifyEmailReturns400OnInvalidToken() throws Exception {
|
||||
when(authService.verifyEmail(any(VerifyEmailRequest.class)))
|
||||
.thenThrow(new IllegalArgumentException("Invalid verification token"));
|
||||
|
||||
VerifyEmailRequest request = new VerifyEmailRequest();
|
||||
request.setToken("bad-token");
|
||||
|
||||
mockMvc.perform(post("/api/auth/verify-email")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(jsonPath("$.detail").value("Invalid verification token"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void verifyEmailReturns400OnExpiredToken() throws Exception {
|
||||
when(authService.verifyEmail(any(VerifyEmailRequest.class)))
|
||||
.thenThrow(new IllegalArgumentException("Verification token has expired"));
|
||||
|
||||
VerifyEmailRequest request = new VerifyEmailRequest();
|
||||
request.setToken("expired-token");
|
||||
|
||||
mockMvc.perform(post("/api/auth/verify-email")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(jsonPath("$.detail").value("Verification token has expired"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void resendVerificationReturns200() throws Exception {
|
||||
when(authService.resendVerification(any(ResendVerificationRequest.class)))
|
||||
.thenReturn(new RegistrationResponse("If this email is available, a verification link has been sent."));
|
||||
|
||||
ResendVerificationRequest request = new ResendVerificationRequest();
|
||||
request.setEmail("user@example.com");
|
||||
|
||||
mockMvc.perform(post("/api/auth/resend-verification")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.message").value("If this email is available, a verification link has been sent."));
|
||||
}
|
||||
|
||||
@Test
|
||||
void setPasswordReturns200() throws Exception {
|
||||
SetPasswordRequest request = new SetPasswordRequest();
|
||||
request.setSetupToken("setup-token-123");
|
||||
request.setPassword("new-password");
|
||||
|
||||
mockMvc.perform(post("/api/auth/set-password")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
void setPasswordReturns400OnInvalidToken() throws Exception {
|
||||
doThrow(new IllegalArgumentException("Invalid setup token"))
|
||||
.when(authService).setPassword(any(SetPasswordRequest.class));
|
||||
|
||||
SetPasswordRequest request = new SetPasswordRequest();
|
||||
request.setSetupToken("bad-token");
|
||||
request.setPassword("new-password");
|
||||
|
||||
mockMvc.perform(post("/api/auth/set-password")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(request)))
|
||||
.andExpect(status().isBadRequest())
|
||||
.andExpect(jsonPath("$.detail").value("Invalid setup token"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,5 +63,6 @@ class UserTest {
|
||||
.build();
|
||||
|
||||
assertFalse(user.isEmailVerified());
|
||||
assertEquals(AuthProvider.LOCAL, user.getProvider());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,58 +4,110 @@ import com.krrishg.dto.AuthResponse;
|
||||
import com.krrishg.dto.LoginRequest;
|
||||
import com.krrishg.dto.RefreshTokenRequest;
|
||||
import com.krrishg.dto.RegisterRequest;
|
||||
import com.krrishg.dto.RegistrationResponse;
|
||||
import com.krrishg.dto.ResendVerificationRequest;
|
||||
import com.krrishg.dto.SetPasswordRequest;
|
||||
import com.krrishg.dto.VerifyEmailRequest;
|
||||
import com.krrishg.dto.VerifyEmailResponse;
|
||||
import com.krrishg.model.User;
|
||||
import com.krrishg.model.VerificationToken;
|
||||
import com.krrishg.support.FakeJwtConfig;
|
||||
import com.krrishg.support.FakeUserRepository;
|
||||
import com.krrishg.support.FakeVerificationTokenRepository;
|
||||
import com.krrishg.support.StubEmailService;
|
||||
import com.krrishg.support.StubPasswordEncoder;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class AuthServiceTest {
|
||||
|
||||
private FakeUserRepository userRepository;
|
||||
private FakeVerificationTokenRepository tokenRepository;
|
||||
private StubEmailService emailService;
|
||||
private AuthService authService;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
userRepository = new FakeUserRepository();
|
||||
authService = new AuthService(userRepository, new StubPasswordEncoder(), new FakeJwtConfig());
|
||||
tokenRepository = new FakeVerificationTokenRepository();
|
||||
emailService = new StubEmailService();
|
||||
authService = new AuthService(userRepository, new StubPasswordEncoder(),
|
||||
new FakeJwtConfig(), tokenRepository, emailService, 1440);
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerCreatesUserAndReturnsTokens() {
|
||||
void registerCreatesUserAndSendsVerification() {
|
||||
RegisterRequest request = new RegisterRequest();
|
||||
request.setEmail("new@example.com");
|
||||
request.setPassword("password123");
|
||||
request.setName("New User");
|
||||
|
||||
AuthResponse response = authService.register(request);
|
||||
RegistrationResponse response = authService.register(request);
|
||||
|
||||
assertNotNull(response.getAccessToken());
|
||||
assertNotNull(response.getRefreshToken());
|
||||
assertEquals("Bearer", response.getTokenType());
|
||||
assertEquals("new@example.com", response.getUser().getEmail());
|
||||
assertEquals("New User", response.getUser().getName());
|
||||
assertEquals("If this email is available, a verification link has been sent.", response.getMessage());
|
||||
assertTrue(userRepository.findByEmail("new@example.com").isPresent());
|
||||
assertFalse(userRepository.findByEmail("new@example.com").get().isEmailVerified());
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerThrowsOnDuplicateEmail() {
|
||||
void registerSendsVerificationEmail() {
|
||||
RegisterRequest request = new RegisterRequest();
|
||||
request.setEmail("dup@example.com");
|
||||
request.setEmail("emailtest@example.com");
|
||||
request.setPassword("password123");
|
||||
request.setName("User");
|
||||
request.setName("Email Test");
|
||||
|
||||
authService.register(request);
|
||||
|
||||
RegisterRequest duplicate = new RegisterRequest();
|
||||
duplicate.setEmail("dup@example.com");
|
||||
duplicate.setPassword("password456");
|
||||
duplicate.setName("Other");
|
||||
assertEquals("emailtest@example.com", emailService.getLastTo());
|
||||
assertNotNull(emailService.getLastToken());
|
||||
assertEquals(1, emailService.getSendCount());
|
||||
}
|
||||
|
||||
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||
() -> authService.register(duplicate));
|
||||
assertEquals("Email already registered", ex.getMessage());
|
||||
@Test
|
||||
void registerReturnsGenericMessageForExistingVerifiedEmail() {
|
||||
User user = User.builder()
|
||||
.email("verified@example.com")
|
||||
.name("Verified")
|
||||
.emailVerified(true)
|
||||
.build();
|
||||
user.onCreate();
|
||||
userRepository.save(user);
|
||||
|
||||
RegisterRequest request = new RegisterRequest();
|
||||
request.setEmail("verified@example.com");
|
||||
request.setPassword("password123");
|
||||
request.setName("Should Not Matter");
|
||||
|
||||
RegistrationResponse response = authService.register(request);
|
||||
|
||||
assertEquals("If this email is available, a verification link has been sent.", response.getMessage());
|
||||
assertEquals(0, emailService.getSendCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerResendsForExistingUnverifiedEmail() {
|
||||
User user = User.builder()
|
||||
.email("unverified@example.com")
|
||||
.name("Unverified")
|
||||
.emailVerified(false)
|
||||
.build();
|
||||
user.onCreate();
|
||||
userRepository.save(user);
|
||||
|
||||
RegisterRequest request = new RegisterRequest();
|
||||
request.setEmail("unverified@example.com");
|
||||
request.setPassword("newpassword");
|
||||
request.setName("New Name");
|
||||
|
||||
RegistrationResponse response = authService.register(request);
|
||||
|
||||
assertEquals("If this email is available, a verification link has been sent.", response.getMessage());
|
||||
assertEquals(1, emailService.getSendCount());
|
||||
assertEquals("unverified@example.com", emailService.getLastTo());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -65,19 +117,23 @@ class AuthServiceTest {
|
||||
request.setPassword("password123");
|
||||
request.setName("User");
|
||||
|
||||
AuthResponse response = authService.register(request);
|
||||
authService.register(request);
|
||||
|
||||
assertEquals("uppercase@example.com", response.getUser().getEmail());
|
||||
assertTrue(userRepository.findByEmail("uppercase@example.com").isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
void loginWithValidCredentialsReturnsTokens() {
|
||||
void loginWithValidCredentialsAndVerifiedEmailReturnsTokens() {
|
||||
RegisterRequest reg = new RegisterRequest();
|
||||
reg.setEmail("login@example.com");
|
||||
reg.setPassword("password123");
|
||||
reg.setName("Login User");
|
||||
authService.register(reg);
|
||||
|
||||
User user = userRepository.findByEmail("login@example.com").get();
|
||||
user.setEmailVerified(true);
|
||||
userRepository.save(user);
|
||||
|
||||
LoginRequest login = new LoginRequest();
|
||||
login.setEmail("login@example.com");
|
||||
login.setPassword("password123");
|
||||
@@ -89,6 +145,23 @@ class AuthServiceTest {
|
||||
assertEquals("login@example.com", response.getUser().getEmail());
|
||||
}
|
||||
|
||||
@Test
|
||||
void loginThrowsWhenEmailNotVerified() {
|
||||
RegisterRequest reg = new RegisterRequest();
|
||||
reg.setEmail("unverified@example.com");
|
||||
reg.setPassword("password123");
|
||||
reg.setName("Unverified");
|
||||
authService.register(reg);
|
||||
|
||||
LoginRequest login = new LoginRequest();
|
||||
login.setEmail("unverified@example.com");
|
||||
login.setPassword("password123");
|
||||
|
||||
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||
() -> authService.login(login));
|
||||
assertEquals("Please verify your email address before logging in", ex.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void loginThrowsOnWrongPassword() {
|
||||
RegisterRequest reg = new RegisterRequest();
|
||||
@@ -97,6 +170,10 @@ class AuthServiceTest {
|
||||
reg.setName("User");
|
||||
authService.register(reg);
|
||||
|
||||
User user = userRepository.findByEmail("wrongpw@example.com").get();
|
||||
user.setEmailVerified(true);
|
||||
userRepository.save(user);
|
||||
|
||||
LoginRequest login = new LoginRequest();
|
||||
login.setEmail("wrongpw@example.com");
|
||||
login.setPassword("wrongpw");
|
||||
@@ -117,16 +194,305 @@ class AuthServiceTest {
|
||||
assertEquals("Invalid email or password", ex.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void verifyEmailMarksUserVerifiedAndReturnsSetupToken() {
|
||||
User user = User.builder()
|
||||
.email("verify@example.com")
|
||||
.name("Verify")
|
||||
.password("encoded")
|
||||
.emailVerified(false)
|
||||
.build();
|
||||
user.onCreate();
|
||||
userRepository.save(user);
|
||||
|
||||
VerificationToken token = VerificationToken.builder()
|
||||
.userId(user.getId())
|
||||
.token("valid-token-123")
|
||||
.expiryDate(LocalDateTime.now().plusHours(24))
|
||||
.used(false)
|
||||
.build();
|
||||
token.onCreate();
|
||||
tokenRepository.save(token);
|
||||
|
||||
VerifyEmailRequest request = new VerifyEmailRequest();
|
||||
request.setToken("valid-token-123");
|
||||
|
||||
VerifyEmailResponse response = authService.verifyEmail(request);
|
||||
|
||||
assertEquals("Email verified successfully", response.getMessage());
|
||||
assertNotNull(response.getSetupToken());
|
||||
|
||||
User updatedUser = userRepository.findById(user.getId()).get();
|
||||
assertTrue(updatedUser.isEmailVerified());
|
||||
}
|
||||
|
||||
@Test
|
||||
void verifyEmailThrowsForInvalidToken() {
|
||||
VerifyEmailRequest request = new VerifyEmailRequest();
|
||||
request.setToken("nonexistent-token");
|
||||
|
||||
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||
() -> authService.verifyEmail(request));
|
||||
assertEquals("Invalid verification token", ex.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void verifyEmailThrowsForUsedToken() {
|
||||
User user = User.builder()
|
||||
.email("usedtoken@example.com")
|
||||
.name("Used")
|
||||
.emailVerified(false)
|
||||
.build();
|
||||
user.onCreate();
|
||||
userRepository.save(user);
|
||||
|
||||
VerificationToken token = VerificationToken.builder()
|
||||
.userId(user.getId())
|
||||
.token("used-token")
|
||||
.expiryDate(LocalDateTime.now().plusHours(24))
|
||||
.used(true)
|
||||
.build();
|
||||
token.onCreate();
|
||||
tokenRepository.save(token);
|
||||
|
||||
VerifyEmailRequest request = new VerifyEmailRequest();
|
||||
request.setToken("used-token");
|
||||
|
||||
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||
() -> authService.verifyEmail(request));
|
||||
assertEquals("Verification token has already been used", ex.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void verifyEmailThrowsForExpiredToken() {
|
||||
User user = User.builder()
|
||||
.email("expired@example.com")
|
||||
.name("Expired")
|
||||
.emailVerified(false)
|
||||
.build();
|
||||
user.onCreate();
|
||||
userRepository.save(user);
|
||||
|
||||
VerificationToken token = VerificationToken.builder()
|
||||
.userId(user.getId())
|
||||
.token("expired-token")
|
||||
.expiryDate(LocalDateTime.now().minusHours(1))
|
||||
.used(false)
|
||||
.build();
|
||||
token.onCreate();
|
||||
tokenRepository.save(token);
|
||||
|
||||
VerifyEmailRequest request = new VerifyEmailRequest();
|
||||
request.setToken("expired-token");
|
||||
|
||||
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||
() -> authService.verifyEmail(request));
|
||||
assertEquals("Verification token has expired", ex.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void setPasswordUpdatesPassword() {
|
||||
User user = User.builder()
|
||||
.email("setpw@example.com")
|
||||
.name("SetPw")
|
||||
.password("old-encoded")
|
||||
.emailVerified(true)
|
||||
.build();
|
||||
user.onCreate();
|
||||
userRepository.save(user);
|
||||
|
||||
VerificationToken token = VerificationToken.builder()
|
||||
.userId(user.getId())
|
||||
.token("verify-token")
|
||||
.setupToken("setup-token-123")
|
||||
.setupTokenUsed(false)
|
||||
.expiryDate(LocalDateTime.now().plusHours(24))
|
||||
.used(true)
|
||||
.build();
|
||||
token.onCreate();
|
||||
tokenRepository.save(token);
|
||||
|
||||
SetPasswordRequest request = new SetPasswordRequest();
|
||||
request.setSetupToken("setup-token-123");
|
||||
request.setPassword("new-password");
|
||||
|
||||
authService.setPassword(request);
|
||||
|
||||
User updatedUser = userRepository.findById(user.getId()).get();
|
||||
assertTrue(updatedUser.getPassword().contains("new-password"));
|
||||
|
||||
VerificationToken updatedToken = tokenRepository.findByToken("verify-token").get();
|
||||
assertTrue(updatedToken.isSetupTokenUsed());
|
||||
}
|
||||
|
||||
@Test
|
||||
void setPasswordThrowsForInvalidSetupToken() {
|
||||
SetPasswordRequest request = new SetPasswordRequest();
|
||||
request.setSetupToken("invalid-setup-token");
|
||||
request.setPassword("new-password");
|
||||
|
||||
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||
() -> authService.setPassword(request));
|
||||
assertEquals("Invalid setup token", ex.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void setPasswordThrowsWhenEmailNotVerifiedFirst() {
|
||||
User user = User.builder()
|
||||
.email("notverified@example.com")
|
||||
.name("NotVerified")
|
||||
.emailVerified(false)
|
||||
.build();
|
||||
user.onCreate();
|
||||
userRepository.save(user);
|
||||
|
||||
VerificationToken token = VerificationToken.builder()
|
||||
.userId(user.getId())
|
||||
.token("unused-verify-token")
|
||||
.setupToken("setup-token-bad")
|
||||
.setupTokenUsed(false)
|
||||
.expiryDate(LocalDateTime.now().plusHours(24))
|
||||
.used(false)
|
||||
.build();
|
||||
token.onCreate();
|
||||
tokenRepository.save(token);
|
||||
|
||||
SetPasswordRequest request = new SetPasswordRequest();
|
||||
request.setSetupToken("setup-token-bad");
|
||||
request.setPassword("new-password");
|
||||
|
||||
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||
() -> authService.setPassword(request));
|
||||
assertEquals("Email must be verified first", ex.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void setPasswordThrowsForAlreadyUsedSetupToken() {
|
||||
User user = User.builder()
|
||||
.email("alreadyset@example.com")
|
||||
.name("AlreadySet")
|
||||
.emailVerified(true)
|
||||
.build();
|
||||
user.onCreate();
|
||||
userRepository.save(user);
|
||||
|
||||
VerificationToken token = VerificationToken.builder()
|
||||
.userId(user.getId())
|
||||
.token("used-verify-token")
|
||||
.setupToken("already-used-setup")
|
||||
.setupTokenUsed(true)
|
||||
.expiryDate(LocalDateTime.now().plusHours(24))
|
||||
.used(true)
|
||||
.build();
|
||||
token.onCreate();
|
||||
tokenRepository.save(token);
|
||||
|
||||
SetPasswordRequest request = new SetPasswordRequest();
|
||||
request.setSetupToken("already-used-setup");
|
||||
request.setPassword("new-password");
|
||||
|
||||
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||
() -> authService.setPassword(request));
|
||||
assertEquals("Setup token has already been used", ex.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void setPasswordThrowsForExpiredSetupToken() {
|
||||
User user = User.builder()
|
||||
.email("expiredsetup@example.com")
|
||||
.name("ExpiredSetup")
|
||||
.emailVerified(true)
|
||||
.build();
|
||||
user.onCreate();
|
||||
userRepository.save(user);
|
||||
|
||||
VerificationToken token = VerificationToken.builder()
|
||||
.userId(user.getId())
|
||||
.token("expired-verify-token")
|
||||
.setupToken("expired-setup-token")
|
||||
.setupTokenUsed(false)
|
||||
.expiryDate(LocalDateTime.now().minusHours(1))
|
||||
.used(true)
|
||||
.build();
|
||||
token.onCreate();
|
||||
tokenRepository.save(token);
|
||||
|
||||
SetPasswordRequest request = new SetPasswordRequest();
|
||||
request.setSetupToken("expired-setup-token");
|
||||
request.setPassword("new-password");
|
||||
|
||||
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||
() -> authService.setPassword(request));
|
||||
assertEquals("Setup token has expired", ex.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
void resendVerificationSendsNewToken() {
|
||||
User user = User.builder()
|
||||
.email("resend@example.com")
|
||||
.name("Resend")
|
||||
.emailVerified(false)
|
||||
.build();
|
||||
user.onCreate();
|
||||
userRepository.save(user);
|
||||
|
||||
ResendVerificationRequest request = new ResendVerificationRequest();
|
||||
request.setEmail("resend@example.com");
|
||||
|
||||
RegistrationResponse response = authService.resendVerification(request);
|
||||
|
||||
assertEquals("If this email is available, a verification link has been sent.", response.getMessage());
|
||||
assertEquals(1, emailService.getSendCount());
|
||||
assertEquals("resend@example.com", emailService.getLastTo());
|
||||
}
|
||||
|
||||
@Test
|
||||
void resendVerificationReturnsGenericForNonExistentEmail() {
|
||||
ResendVerificationRequest request = new ResendVerificationRequest();
|
||||
request.setEmail("nonexistent@example.com");
|
||||
|
||||
RegistrationResponse response = authService.resendVerification(request);
|
||||
|
||||
assertEquals("If this email is available, a verification link has been sent.", response.getMessage());
|
||||
assertEquals(0, emailService.getSendCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
void resendVerificationReturnsGenericForAlreadyVerifiedEmail() {
|
||||
User user = User.builder()
|
||||
.email("alreadyverified@example.com")
|
||||
.name("AlreadyVerified")
|
||||
.emailVerified(true)
|
||||
.build();
|
||||
user.onCreate();
|
||||
userRepository.save(user);
|
||||
|
||||
ResendVerificationRequest request = new ResendVerificationRequest();
|
||||
request.setEmail("alreadyverified@example.com");
|
||||
|
||||
RegistrationResponse response = authService.resendVerification(request);
|
||||
|
||||
assertEquals("If this email is available, a verification link has been sent.", response.getMessage());
|
||||
assertEquals(0, emailService.getSendCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshTokenReturnsNewTokens() {
|
||||
RegisterRequest reg = new RegisterRequest();
|
||||
reg.setEmail("refresh@example.com");
|
||||
reg.setPassword("password123");
|
||||
reg.setName("Refresh User");
|
||||
AuthResponse initial = authService.register(reg);
|
||||
authService.register(reg);
|
||||
|
||||
User user = userRepository.findByEmail("refresh@example.com").get();
|
||||
user.setEmailVerified(true);
|
||||
userRepository.save(user);
|
||||
|
||||
FakeJwtConfig jwtConfig = new FakeJwtConfig();
|
||||
String token = jwtConfig.generateRefreshToken(user);
|
||||
|
||||
RefreshTokenRequest refreshRequest = new RefreshTokenRequest();
|
||||
refreshRequest.setRefreshToken(initial.getRefreshToken());
|
||||
refreshRequest.setRefreshToken(token);
|
||||
|
||||
AuthResponse response = authService.refreshToken(refreshRequest);
|
||||
|
||||
@@ -151,6 +517,7 @@ class AuthServiceTest {
|
||||
.email("deleted@example.com")
|
||||
.name("Deleted")
|
||||
.build();
|
||||
user.onCreate();
|
||||
userRepository.save(user);
|
||||
|
||||
FakeJwtConfig jwtConfig = new FakeJwtConfig();
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.krrishg.support;
|
||||
|
||||
import com.krrishg.model.VerificationToken;
|
||||
import com.krrishg.repository.VerificationTokenRepository;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class FakeVerificationTokenRepository extends InMemoryRepository<VerificationToken, UUID> implements VerificationTokenRepository {
|
||||
|
||||
@Override
|
||||
protected UUID getId(VerificationToken entity) {
|
||||
return entity.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected VerificationToken setId(VerificationToken entity, UUID id) {
|
||||
entity.setId(id);
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UUID generateId() {
|
||||
return UUID.randomUUID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<VerificationToken> findByToken(String token) {
|
||||
return store.values().stream()
|
||||
.filter(t -> t.getToken().equals(token))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<VerificationToken> findBySetupToken(String setupToken) {
|
||||
return store.values().stream()
|
||||
.filter(t -> setupToken.equals(t.getSetupToken()))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteByUserId(UUID userId) {
|
||||
store.values().removeIf(t -> t.getUserId().equals(userId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VerificationToken> findByUsedFalseAndExpiryDateBefore(LocalDateTime now) {
|
||||
return store.values().stream()
|
||||
.filter(t -> !t.isUsed())
|
||||
.filter(t -> t.getExpiryDate().isBefore(now))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.krrishg.support;
|
||||
|
||||
import com.krrishg.service.EmailService;
|
||||
|
||||
public class StubEmailService extends EmailService {
|
||||
|
||||
private String lastTo;
|
||||
private String lastToken;
|
||||
private int sendCount;
|
||||
|
||||
public StubEmailService() {
|
||||
super(null, "http://localhost:4200");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendVerificationEmail(String to, String name, String token) {
|
||||
this.lastTo = to;
|
||||
this.lastToken = token;
|
||||
this.sendCount++;
|
||||
}
|
||||
|
||||
public String getLastTo() {
|
||||
return lastTo;
|
||||
}
|
||||
|
||||
public String getLastToken() {
|
||||
return lastToken;
|
||||
}
|
||||
|
||||
public int getSendCount() {
|
||||
return sendCount;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
lastTo = null;
|
||||
lastToken = null;
|
||||
sendCount = 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user