/**
* =============================================================================
*
* ORCID (R) Open Source
* http://orcid.org
*
* Copyright (c) 2012-2014 ORCID, Inc.
* Licensed under an MIT-Style License (MIT)
* http://orcid.org/open-source-license
*
* This copyright and license information (including a link to the full license)
* shall be included in its entirety in all copies or substantial portion of
* the software.
*
* =============================================================================
*/
package org.orcid.frontend.web.controllers;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.Arrays;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.orcid.core.manager.EncryptionManager;
import org.orcid.core.manager.LoadOptions;
import org.orcid.core.manager.OrcidProfileManager;
import org.orcid.core.manager.RegistrationManager;
import org.orcid.frontend.web.forms.OneTimeResetPasswordForm;
import org.orcid.jaxb.model.message.DeactivationDate;
import org.orcid.jaxb.model.message.OrcidHistory;
import org.orcid.jaxb.model.message.OrcidInternal;
import org.orcid.jaxb.model.message.OrcidProfile;
import org.orcid.jaxb.model.message.SecurityDetails;
import org.orcid.jaxb.model.message.SecurityQuestionId;
import org.orcid.pojo.EmailRequest;
import org.orcid.test.DBUnitTest;
import org.orcid.test.OrcidJUnit4ClassRunner;
import org.orcid.test.TargetProxyHelper;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.validation.BindingResult;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.google.common.collect.Lists;
@RunWith(OrcidJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = { "classpath:orcid-frontend-web-servlet.xml", "classpath:orcid-core-context.xml", "classpath:statistics-core-context.xml" })
public class PasswordResetControllerTest extends DBUnitTest {
private static final List<String> DATA_FILES = Arrays.asList("/data/EmptyEntityData.xml", "/data/SecurityQuestionEntityData.xml",
"/data/SourceClientDetailsEntityData.xml", "/data/ProfileEntityData.xml", "/data/ClientDetailsEntityData.xml", "/data/RecordNameEntityData.xml",
"/data/BiographyEntityData.xml");
@Resource(name = "passwordResetController")
private PasswordResetController passwordResetController;
@Mock
private RegistrationManager registrationManager;
@Mock
private OrcidProfileManager orcidProfileManager;
@Mock
private EncryptionManager encryptionManager;
@Mock
private HttpServletRequest servletRequest;
@Mock
private HttpServletResponse servletResponse;
@BeforeClass
public static void beforeClass() throws Exception {
initDBUnitData(DATA_FILES);
}
@AfterClass
public static void afterClass() throws Exception {
removeDBUnitData(Lists.reverse(DATA_FILES));
}
@Before
public void before() {
MockitoAnnotations.initMocks(this);
TargetProxyHelper.injectIntoProxy(passwordResetController, "registrationManager", registrationManager);
TargetProxyHelper.injectIntoProxy(passwordResetController, "orcidProfileManager", orcidProfileManager);
TargetProxyHelper.injectIntoProxy(passwordResetController, "encryptionManager", encryptionManager);
}
@Test
public void testPasswordResetUserNotFound() {
when(orcidProfileManager.retrieveOrcidProfileByEmail(Mockito.anyString(), Mockito.any(LoadOptions.class))).thenReturn(null);
EmailRequest resetRequest = new EmailRequest();
resetRequest = passwordResetController.issuePasswordResetRequest(new MockHttpServletRequest(), resetRequest).getBody();
assertNotNull(resetRequest.getErrors());
assertFalse(resetRequest.getErrors().isEmpty());
}
@Test
public void testPasswordResetUserDeactivated() throws DatatypeConfigurationException {
GregorianCalendar c = new GregorianCalendar();
c.setTime(new Date());
XMLGregorianCalendar date = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);
OrcidHistory orcidHistory = new OrcidHistory();
orcidHistory.setDeactivationDate(new DeactivationDate(date));
OrcidProfile deactivatedProfile = new OrcidProfile();
deactivatedProfile.setOrcidHistory(orcidHistory);
when(orcidProfileManager.retrieveOrcidProfileByEmail(Mockito.anyString(), Mockito.any(LoadOptions.class))).thenReturn(deactivatedProfile);
EmailRequest resetRequest = new EmailRequest();
resetRequest = passwordResetController.issuePasswordResetRequest(new MockHttpServletRequest(), resetRequest).getBody();
assertNotNull(resetRequest.getErrors());
assertFalse(resetRequest.getErrors().isEmpty());
}
@Test
public void testPasswordResetLinkExpired() throws Exception {
HttpServletRequest servletRequest = mock(HttpServletRequest.class);
RedirectAttributes redirectAttributes = mock(RedirectAttributes.class);
when(encryptionManager.decryptForExternalUse(any(String.class))).thenReturn("email=any@orcid.org&issueDate=1970-05-29T17:04:27");
ModelAndView modelAndView = passwordResetController.resetPasswordEmail(servletRequest, "randomString", redirectAttributes);
assertEquals("redirect:/reset-password?expired=true", modelAndView.getViewName());
verify(redirectAttributes, times(1)).addFlashAttribute("passwordResetLinkExpired", true);
}
@Test
public void testPasswordResetLinkValidLinkDirectsToConsolidatedScreenDirectlyWhenNoSecurityQuestion() throws Exception {
HttpServletRequest servletRequest = mock(HttpServletRequest.class);
RedirectAttributes redirectAttributes = mock(RedirectAttributes.class);
when(encryptionManager.decryptForExternalUse(any(String.class))).thenReturn("email=any@orcid.org&issueDate=2070-05-29T17:04:27");
when(orcidProfileManager.retrieveOrcidProfileByEmail(eq("any@orcid.org"), Matchers.<LoadOptions> any())).thenReturn(new OrcidProfile());
ModelAndView modelAndView = passwordResetController.resetPasswordEmail(servletRequest, "randomString", redirectAttributes);
assertEquals("password_one_time_reset_optional_security_questions", modelAndView.getViewName());
verify(redirectAttributes, never()).addFlashAttribute("passwordResetLinkExpired", true);
}
@Test
public void testPasswordResetLinkValidLinkDirectsToSecurityQuestionScreenWhenSecurityQuestionPresent() throws Exception {
HttpServletRequest servletRequest = mock(HttpServletRequest.class);
RedirectAttributes redirectAttributes = mock(RedirectAttributes.class);
when(encryptionManager.decryptForExternalUse(any(String.class))).thenReturn("email=any@orcid.org&issueDate=2070-05-29T17:04:27");
when(orcidProfileManager.retrieveOrcidProfileByEmail(eq("any@orcid.org"), Matchers.<LoadOptions> any())).thenReturn(orcidWithSecurityQuestion());
ModelAndView modelAndView = passwordResetController.resetPasswordEmail(servletRequest, "randomString", redirectAttributes);
assertEquals("password_one_time_reset_optional_security_questions", modelAndView.getViewName());
verify(redirectAttributes, never()).addFlashAttribute("passwordResetLinkExpired", true);
}
@Test
public void testSubmitConsolidatedPasswordReset() throws Exception {
RedirectAttributes redirectAttributes = mock(RedirectAttributes.class);
BindingResult bindingResult = mock(BindingResult.class);
OneTimeResetPasswordForm oneTimeResetPasswordForm = new OneTimeResetPasswordForm();
oneTimeResetPasswordForm.setEncryptedEmail("encrypted string not expired");
when(encryptionManager.decryptForExternalUse(any(String.class))).thenReturn("email=any@orcid.org&issueDate=2070-05-29T17:04:27");
when(bindingResult.hasErrors()).thenReturn(true);
oneTimeResetPasswordForm = passwordResetController.submitPasswordReset(servletRequest, servletResponse, oneTimeResetPasswordForm);
assertFalse(oneTimeResetPasswordForm.getErrors().isEmpty());
oneTimeResetPasswordForm.setPassword("Password#123");
when(bindingResult.hasErrors()).thenReturn(false);
when(orcidProfileManager.retrieveOrcidProfileByEmail(eq("any@orcid.org"), Matchers.<LoadOptions> any())).thenReturn(orcidWithSecurityQuestion());
oneTimeResetPasswordForm = passwordResetController.submitPasswordReset(servletRequest, servletResponse, oneTimeResetPasswordForm);
assertTrue(oneTimeResetPasswordForm.getSuccessRedirectLocation().equals("http://testserver.orcid.org/my-orcid")
|| oneTimeResetPasswordForm.getSuccessRedirectLocation().equals("https://localhost:8443/orcid-web/my-orcid"));
verify(redirectAttributes, never()).addFlashAttribute("passwordResetLinkExpired", true);
when(encryptionManager.decryptForExternalUse(any(String.class))).thenReturn("email=any@orcid.org&issueDate=1970-05-29T17:04:27");
oneTimeResetPasswordForm = passwordResetController.submitPasswordReset(servletRequest, servletResponse, oneTimeResetPasswordForm);
assertFalse(oneTimeResetPasswordForm.getErrors().isEmpty());
}
@Test
public void testResetPasswordDontFailIfAnyFieldIsEmtpy() {
OneTimeResetPasswordForm form = new OneTimeResetPasswordForm();
passwordResetController.resetPasswordConfirmValidate(form);
form.setPassword("");
form.setRetypedPassword(null);
passwordResetController.resetPasswordConfirmValidate(form);
form.setPassword(null);
form.setRetypedPassword("");
passwordResetController.resetPasswordConfirmValidate(form);
}
private OrcidProfile orcidWithSecurityQuestion() {
OrcidProfile orcidProfile = new OrcidProfile();
orcidProfile.setSecurityQuestionAnswer("Answer");
OrcidInternal orcidInternal = new OrcidInternal();
SecurityDetails securityDetails = new SecurityDetails();
securityDetails.setSecurityQuestionId(new SecurityQuestionId(3));
orcidInternal.setSecurityDetails(securityDetails);
orcidProfile.setOrcidInternal(orcidInternal);
return orcidProfile;
}
}