package com.porterhead.user; import com.porterhead.mail.EmailServiceTokenModel; import com.porterhead.mail.MailSenderService; import com.porterhead.user.api.LostPasswordRequest; import com.porterhead.user.api.PasswordRequest; import com.porterhead.user.exception.AlreadyVerifiedException; import com.porterhead.user.exception.TokenHasExpiredException; import com.porterhead.user.exception.TokenNotFoundException; import com.porterhead.user.exception.UserNotFoundException; import org.apache.commons.codec.binary.Base64; import org.hamcrest.Matchers; import org.junit.Before; import org.junit.Test; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.StandardPasswordEncoder; import javax.validation.Validation; import javax.validation.Validator; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.UUID; import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.*; /** * @version 1.0 * @author: Iain Porter * @since 13/05/2013 */ public class VerificationServiceTest { private MailSenderService mailSenderService; private UserRepository userRepository; private VerificationTokenRepository tokenRepository; private List<String> tokens; private VerificationTokenService verificationTokenService; private Validator validator; private PasswordEncoder passwordEncoder; @Before public void setUp() { tokens = new ArrayList<String>(); mailSenderService = new MailSenderService() { @Override public EmailServiceTokenModel sendVerificationEmail(EmailServiceTokenModel emailServiceTokenModel) { tokens.add(emailServiceTokenModel.getToken()); return emailServiceTokenModel; } @Override public EmailServiceTokenModel sendRegistrationEmail(EmailServiceTokenModel emailServiceTokenModel) { tokens.add(emailServiceTokenModel.getToken()); return emailServiceTokenModel; } @Override public EmailServiceTokenModel sendLostPasswordEmail(EmailServiceTokenModel emailServiceTokenModel) { tokens.add(emailServiceTokenModel.getToken()); return emailServiceTokenModel; } }; validator = Validation.buildDefaultValidatorFactory().getValidator(); userRepository = mock(UserRepository.class); tokenRepository = mock(VerificationTokenRepository.class); passwordEncoder = new StandardPasswordEncoder(""); verificationTokenService = new VerificationTokenServiceImpl(userRepository, tokenRepository, mailSenderService, validator, passwordEncoder); ((VerificationTokenServiceImpl) verificationTokenService).setHostNameUrl("http://localhost:8080"); ((VerificationTokenServiceImpl) verificationTokenService).setLostPasswordTokenExpiryTimeInMinutes(120); ((VerificationTokenServiceImpl) verificationTokenService).setEmailVerificationTokenExpiryTimeInMinutes(120); ((VerificationTokenServiceImpl) verificationTokenService).setEmailRegistrationTokenExpiryTimeInMinutes(120); } @Test public void sendLostPasswordToken() { User user = generateTestUser(); when(userRepository.findByEmailAddress(user.getEmailAddress())).thenReturn(user); VerificationToken token = verificationTokenService.sendLostPasswordToken(new LostPasswordRequest(user.getEmailAddress())); when(tokenRepository.findByUserId(user.getId())).thenReturn(Arrays.asList(token)); List<VerificationToken> savedTokens = tokenRepository.findByUserId(user.getId()); assertThat(savedTokens.size(), is(1)); assertThat(savedTokens.get(0), is(token)); assertThat(token, is(not(Matchers.<Object>nullValue()))); assertThat(tokens.size(), is(1)); String sentToken = tokens.get(0); assertThat(sentToken, is(not(nullValue()))); assertThat(sentToken, is(token.getToken())); assertThat(token.getTokenType(), is(VerificationTokenType.lostPassword)); } @Test public void sendLostPasswordTokenAgain() { User user = generateTestUser(); when(userRepository.findByEmailAddress(user.getEmailAddress())).thenReturn(user); VerificationToken token1 = verificationTokenService.sendLostPasswordToken(new LostPasswordRequest(user.getEmailAddress())); when(tokenRepository.findByUserIdAndTokenType(user.getId(), VerificationTokenType.lostPassword)).thenReturn(Arrays.asList(token1)); VerificationToken token2 = verificationTokenService.sendLostPasswordToken(new LostPasswordRequest(user.getEmailAddress())); assertThat(token1.getId(), is(token2.getId())); verify(tokenRepository, times(1)).save(any(VerificationToken.class)); assertThat(tokens.size(), is(2)); //gateway called twice } @Test public void resetPassword() throws Exception { User user = generateTestUser(); when(userRepository.save(user)).thenReturn(user); when(userRepository.findByEmailAddress(user.getEmailAddress())).thenReturn(user); when(userRepository.findOne(user.getId())).thenReturn(user); VerificationToken token = verificationTokenService.sendLostPasswordToken(new LostPasswordRequest(user.getEmailAddress())); when(tokenRepository.findByToken(token.getToken())).thenReturn(token); String encodedToken = new String(Base64.encodeBase64(token.getToken().getBytes())); VerificationToken verifiedToken = verificationTokenService.resetPassword(encodedToken, new PasswordRequest("newpassword")); assertThat(verifiedToken.isVerified(), is(true)); assertTrue(passwordEncoder.matches("newpassword", user.getHashedPassword())); verify(tokenRepository, times(2)).save(any(VerificationToken.class)); //user should also be verified assertThat(user.isVerified(), is(true)); } @Test public void resetPasswordGetNewToken() { User user = generateTestUser(); when(userRepository.save(user)).thenReturn(user); when(userRepository.findOne(user.getId())).thenReturn(user); when(userRepository.findByEmailAddress(user.getEmailAddress())).thenReturn(user); VerificationToken token = verificationTokenService.sendLostPasswordToken(new LostPasswordRequest(user.getEmailAddress())); when(tokenRepository.findByToken(token.getToken())).thenReturn(token); String encodedToken = new String(Base64.encodeBase64(token.getToken().getBytes())); verificationTokenService.resetPassword(encodedToken, new PasswordRequest("newpassword")); VerificationToken token2 = verificationTokenService.sendLostPasswordToken(new LostPasswordRequest(user.getEmailAddress())); assertThat(token2.getToken(), is(not(token.getToken()))); verify(tokenRepository, times(3)).save(any(VerificationToken.class)); } @Test public void sendEmailToken() { User user = generateTestUser(); when(userRepository.findOne(user.getId())).thenReturn(user); VerificationToken token = verificationTokenService.sendEmailVerificationToken(user.getId()); assertThat(tokens.size(), is(1)); String sentToken = tokens.get(0); assertThat(sentToken, is(not(nullValue()))); assertThat(sentToken, is(token.getToken())); assertThat(token.getTokenType(), is(VerificationTokenType.emailVerification)); verify(tokenRepository, times(1)).save(any(VerificationToken.class)); } @Test public void sendRegistrationToken() { User user = generateTestUser(); when(userRepository.findOne(user.getId())).thenReturn(user); VerificationToken token = verificationTokenService.sendEmailRegistrationToken(user.getId()); assertThat(tokens.size(), is(1)); String sentToken = tokens.get(0); assertThat(sentToken, is(not(nullValue()))); assertThat(sentToken, is(token.getToken())); assertThat(token.getTokenType(), is(VerificationTokenType.emailRegistration)); verify(tokenRepository, times(1)).save(any(VerificationToken.class)); } @Test public void verifyValidToken() { User user = generateTestUser(); when(userRepository.save(user)).thenReturn(user); when(userRepository.findOne(user.getId())).thenReturn(user); VerificationToken token = verificationTokenService.sendEmailVerificationToken(user.getId()); when(tokenRepository.findByToken(token.getToken())).thenReturn(token); String encodedToken = new String(Base64.encodeBase64(token.getToken().getBytes())); VerificationToken verifiedToken = verificationTokenService.verify(encodedToken); assertThat(verifiedToken.isVerified(), is(true)); assertThat(user.isVerified(), is(true)); verify(tokenRepository, times(2)).save(any(VerificationToken.class)); } @Test(expected = TokenHasExpiredException.class) public void tokenHasExpired() { User user = generateTestUser(); VerificationToken token = mock(VerificationToken.class); when(token.getUserId()).thenReturn(user.getId()); when(token.hasExpired()).thenReturn(true); when(token.getToken()).thenReturn(UUID.randomUUID().toString()); when(userRepository.save(user)).thenReturn(user); when(tokenRepository.findByToken(token.getToken())).thenReturn(token); String encodedToken = new String(Base64.encodeBase64(token.getToken().getBytes())); verificationTokenService.verify(encodedToken); } @Test(expected = AlreadyVerifiedException.class) public void tokenAlreadyVerified() { User user = generateTestUser(); VerificationToken token = mock(VerificationToken.class); when(token.getUserId()).thenReturn(user.getId()); when(token.hasExpired()).thenReturn(false); when(token.isVerified()).thenReturn(true); when(token.getToken()).thenReturn(UUID.randomUUID().toString()); when(userRepository.save(user)).thenReturn(user); when(tokenRepository.findByToken(token.getToken())).thenReturn(token); String encodedToken = new String(Base64.encodeBase64(token.getToken().getBytes())); verificationTokenService.verify(encodedToken); } @Test(expected = AlreadyVerifiedException.class) public void userAlreadyVerified() { User user = generateTestUser(); user.setVerified(true); VerificationToken token = mock(VerificationToken.class); when(token.getUserId()).thenReturn(user.getId()); when(token.hasExpired()).thenReturn(false); when(token.isVerified()).thenReturn(false); when(token.getToken()).thenReturn(UUID.randomUUID().toString()); when(userRepository.save(user)).thenReturn(user); when(tokenRepository.findByToken(token.getToken())).thenReturn(token); when(userRepository.findOne(user.getId())).thenReturn(user); String encodedToken = new String(Base64.encodeBase64(token.getToken().getBytes())); verificationTokenService.verify(encodedToken); } @Test(expected = TokenNotFoundException.class) public void tokenNotFound() { VerificationToken token = new VerificationToken(new User(), VerificationTokenType.emailVerification, 120); when(tokenRepository.findByToken(token.getToken())).thenReturn(null); String encodedToken = new String(Base64.encodeBase64(token.getToken().getBytes())); verificationTokenService.verify(encodedToken); } @Test public void generateEmailToken() { User user = generateTestUser(); when(userRepository.findByEmailAddress(user.getEmailAddress())).thenReturn(user); when(userRepository.save(user)).thenReturn(user); VerificationToken token = verificationTokenService.generateEmailVerificationToken(user.getEmailAddress()); assertThat(token, is(not(Matchers.<Object>nullValue()))); assertThat(tokens.size(), is(1)); String sentToken = tokens.get(0); assertThat(sentToken, is(not(nullValue()))); UUID.fromString(sentToken); assertThat(sentToken, is(token.getToken())); verify(tokenRepository, times(1)).save(any(VerificationToken.class)); } private User generateTestUser() { User user = new User(); user.setEmailAddress("test@example.com"); return user; } @Test public void generateEmailTokenAlreadyActive() { User user = generateTestUser(); when(userRepository.findByEmailAddress(user.getEmailAddress())).thenReturn(user); when(userRepository.save(user)).thenReturn(user); VerificationToken token = verificationTokenService.generateEmailVerificationToken(user.getEmailAddress()); when(tokenRepository.findByUserIdAndTokenType(user.getId(), VerificationTokenType.emailVerification)).thenReturn(Arrays.asList(token)); //request it again verificationTokenService.generateEmailVerificationToken(user.getEmailAddress()); verify(tokenRepository, times(1)).save(any(VerificationToken.class)); assertThat(tokens.size(), is(2)); //gateway invoked twice } @Test public void generateEmailTokenAfterExpired() { User user = generateTestUser(); VerificationToken token = mock(VerificationToken.class); when(token.hasExpired()).thenReturn(true); when(token.getTokenType()).thenReturn(VerificationTokenType.emailVerification); when(token.getUserId()).thenReturn(user.getId()); when(userRepository.findByEmailAddress(user.getEmailAddress())).thenReturn(user); when(userRepository.save(user)).thenReturn(user); VerificationToken generatedToken = verificationTokenService.generateEmailVerificationToken(user.getEmailAddress()); assertThat(tokens.size(), is(1)); //gateway invoked once, as first token was manually added verify(tokenRepository, times(1)).save(any(VerificationToken.class)); } @Test(expected = UserNotFoundException.class) public void emailAddressNotFound() { verificationTokenService.generateEmailVerificationToken("test@example.com"); } @Test(expected = AlreadyVerifiedException.class) public void generateEmailTokenAlreadyVerified() { User user = new User(); user.setEmailAddress("test@example.com"); user.setVerified(true); VerificationToken token = mock(VerificationToken.class); when(userRepository.findByEmailAddress(user.getEmailAddress())).thenReturn(user); verificationTokenService.generateEmailVerificationToken(user.getEmailAddress()); } }