package org.molgenis.security.account;
import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.molgenis.auth.User;
import org.molgenis.auth.UserFactory;
import org.molgenis.data.DataService;
import org.molgenis.data.Entity;
import org.molgenis.data.settings.AppSettings;
import org.molgenis.data.support.QueryImpl;
import org.molgenis.security.account.AccountControllerTest.Config;
import org.molgenis.security.captcha.CaptchaException;
import org.molgenis.security.captcha.CaptchaService;
import org.molgenis.security.user.UserService;
import org.molgenis.util.GsonConfig;
import org.molgenis.util.GsonHttpMessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTestNGSpringContextTests;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import java.util.Collections;
import static org.mockito.Mockito.*;
import static org.molgenis.auth.UserMetaData.EMAIL;
import static org.molgenis.auth.UserMetaData.USER;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.testng.Assert.assertEquals;
@WebAppConfiguration
@ContextConfiguration(classes = { Config.class, GsonConfig.class })
public class AccountControllerTest extends AbstractTestNGSpringContextTests
{
@Autowired
private AccountController authenticationController;
@Autowired
private AccountService accountService;
@Autowired
private CaptchaService captchaService;
@Autowired
private GsonHttpMessageConverter gsonHttpMessageConverter;
@Autowired
private AppSettings appSettings;
private MockMvc mockMvc;
@BeforeMethod
public void setUp() throws CaptchaException
{
FreeMarkerViewResolver freeMarkerViewResolver = new FreeMarkerViewResolver();
freeMarkerViewResolver.setSuffix(".ftl");
mockMvc = MockMvcBuilders.standaloneSetup(authenticationController)
.setMessageConverters(new FormHttpMessageConverter(), gsonHttpMessageConverter).build();
reset(appSettings);
reset(captchaService);
when(captchaService.validateCaptcha("validCaptcha")).thenReturn(true);
reset(accountService); // mocks in the config class are not resetted after each test
}
@Test
public void getLoginForm() throws Exception
{
this.mockMvc.perform(get("/account/login")).andExpect(status().isOk()).andExpect(view().name("login-modal"));
}
@Test
public void getPasswordResetForm() throws Exception
{
this.mockMvc.perform(get("/account/password/reset")).andExpect(status().isOk())
.andExpect(view().name("resetpassword-modal"));
}
@Test
public void getRegisterForm() throws Exception
{
this.mockMvc.perform(get("/account/register")).andExpect(status().isOk())
.andExpect(view().name("register-modal")).andExpect(model().attributeExists("countries"));
}
@Test
public void activateUser() throws Exception
{
this.mockMvc.perform(get("/account/activate/123")).andExpect(view().name("forward:/"));
verify(accountService).activateUser("123");
}
@Test
public void registerUser_activationModeUserProxy() throws Exception
{
when(appSettings.getSignUp()).thenReturn(true);
when(appSettings.getSignUpModeration()).thenReturn(false);
this.mockMvc.perform(
post("/account/register").header("X-Forwarded-Host", "website.com").param("username", "admin")
.param("password", "adminpw-invalid").param("confirmPassword", "adminpw-invalid")
.param("email", "admin@molgenis.org").param("lastname", "min").param("firstname", "ad")
.param("captcha", "validCaptcha").contentType(MediaType.APPLICATION_FORM_URLENCODED))
.andExpect(status().isOk()).andExpect(
content().string("{\"message\":\"" + AccountController.REGISTRATION_SUCCESS_MESSAGE_USER + "\"}"));
ArgumentCaptor<User> molgenisUserCaptor = ArgumentCaptor.forClass(User.class);
ArgumentCaptor<String> baseActivationUriCaptor = ArgumentCaptor.forClass(String.class);
verify(accountService).createUser(molgenisUserCaptor.capture(), baseActivationUriCaptor.capture());
assertEquals(baseActivationUriCaptor.getValue(), "http://website.com/account/activate");
}
@Test
public void registerUser_activationModeUserProxyWithScheme() throws Exception
{
when(appSettings.getSignUp()).thenReturn(true);
when(appSettings.getSignUpModeration()).thenReturn(false);
this.mockMvc.perform(
post("/account/register").header("X-Forwarded-Proto", "https").header("X-Forwarded-Host", "website.com")
.param("username", "admin").param("password", "adminpw-invalid")
.param("confirmPassword", "adminpw-invalid").param("email", "admin@molgenis.org")
.param("lastname", "min").param("firstname", "ad").param("captcha", "validCaptcha")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)).andExpect(status().isOk()).andExpect(
content().string("{\"message\":\"" + AccountController.REGISTRATION_SUCCESS_MESSAGE_USER + "\"}"));
ArgumentCaptor<User> molgenisUserCaptor = ArgumentCaptor.forClass(User.class);
ArgumentCaptor<String> baseActivationUriCaptor = ArgumentCaptor.forClass(String.class);
verify(accountService).createUser(molgenisUserCaptor.capture(), baseActivationUriCaptor.capture());
assertEquals(baseActivationUriCaptor.getValue(), "https://website.com/account/activate");
}
@Test
public void registerUser_activationModeUser() throws Exception
{
when(appSettings.getSignUp()).thenReturn(true);
when(appSettings.getSignUpModeration()).thenReturn(false);
this.mockMvc.perform(post("/account/register").param("username", "admin").param("password", "adminpw-invalid")
.param("confirmPassword", "adminpw-invalid").param("email", "admin@molgenis.org")
.param("lastname", "min").param("firstname", "ad").param("captcha", "validCaptcha")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)).andExpect(status().isOk()).andExpect(
content().string("{\"message\":\"" + AccountController.REGISTRATION_SUCCESS_MESSAGE_USER + "\"}"));
verify(captchaService).validateCaptcha("validCaptcha");
}
@Test
public void registerUser_activationModeAdmin() throws Exception
{
when(appSettings.getSignUp()).thenReturn(true);
when(appSettings.getSignUpModeration()).thenReturn(true);
this.mockMvc.perform(post("/account/register").param("username", "admin").param("password", "adminpw-invalid")
.param("confirmPassword", "adminpw-invalid").param("email", "admin@molgenis.org")
.param("lastname", "min").param("firstname", "ad").param("captcha", "validCaptcha")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)).andExpect(status().isOk()).andExpect(
content().string("{\"message\":\"" + AccountController.REGISTRATION_SUCCESS_MESSAGE_ADMIN + "\"}"));
verify(captchaService).validateCaptcha("validCaptcha");
}
@Test
public void registerUser_invalidRegisterRequest() throws Exception
{
// when(accountService.isSelfRegistrationEnabled()).thenReturn(true);
this.mockMvc.perform(post("/account/register").param("username", "admin").param("password", "adminpw-invalid")
.param("confirmPassword", "adminpw-invalid").param("lastname", "min").param("firstname", "ad")
.param("captcha", "validCaptcha").contentType(MediaType.APPLICATION_FORM_URLENCODED))
.andExpect(status().isBadRequest());
verify(captchaService, times(0)).validateCaptcha("validCaptcha");
}
@Test
public void registerUser_passwordNotEqualsConfirmPassword() throws Exception
{
when(appSettings.getSignUp()).thenReturn(true);
this.mockMvc.perform(post("/account/register").param("username", "admin").param("password", "adminpw-invalid")
.param("confirmPassword", "adminpw-invalid-typo").param("email", "admin@molgenis.org")
.param("lastname", "min").param("firstname", "ad").param("captcha", "validCaptcha")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)).andExpect(status().isBadRequest());
verify(captchaService, times(0)).validateCaptcha("validCaptcha");
}
@Test
public void registerUser_invalidCaptcha() throws Exception
{
when(appSettings.getSignUp()).thenReturn(true);
this.mockMvc.perform(post("/account/register").param("username", "admin").param("password", "adminpw-invalid")
.param("confirmPassword", "adminpw-invalid").param("email", "admin@molgenis.org")
.param("lastname", "min").param("firstname", "ad").param("captcha", "invalidCaptcha")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)).andExpect(status().isBadRequest());
}
@Test
public void resetPassword() throws Exception
{
this.mockMvc.perform(post("/account/password/reset").param("email", "admin@molgenis.org")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)).andExpect(status().isNoContent());
verify(accountService).resetPassword("admin@molgenis.org");
}
@Test
public void registerUser_invalidUserField() throws Exception
{
this.mockMvc.perform(post("/account/register").param("username", "admin").param("password", "adminpw-invalid")
.param("email", "admin@molgenis.org").param("lastname", "min").param("firstname", "ad")
.param("captcha", "validCaptcha").contentType(MediaType.APPLICATION_FORM_URLENCODED))
.andExpect(status().isBadRequest());
}
@Configuration
public static class Config
{
@Bean
public AccountController accountController()
{
return new AccountController(accountService(), captchaService(), redirectStrategy(), appSettings(),
molgenisUserFactory());
}
@Bean
public AccountService accountService()
{
return mock(AccountService.class);
}
@Bean
public CaptchaService captchaService()
{
return mock(CaptchaService.class);
}
@Bean
public RedirectStrategy redirectStrategy()
{
return mock(RedirectStrategy.class);
}
@Bean
public AppSettings appSettings()
{
return mock(AppSettings.class);
}
@Bean
public JavaMailSender mailSender()
{
return mock(JavaMailSender.class);
}
@SuppressWarnings("unchecked")
@Bean
public DataService dataService()
{
DataService dataService = mock(DataService.class);
User user = mock(User.class);
when(dataService.findAll(USER, new QueryImpl().eq(EMAIL, "admin@molgenis.org"))).thenReturn(Collections.<Entity>singletonList(user).stream());
return dataService;
}
@Bean
public UserService molgenisUserService()
{
return mock(UserService.class);
}
@Bean
public UserFactory molgenisUserFactory()
{
UserFactory userFactory = mock(UserFactory.class);
when(userFactory.create()).thenAnswer(new Answer<User>()
{
@Override
public User answer(InvocationOnMock invocationOnMock) throws Throwable
{
return mock(User.class);
}
});
return userFactory;
}
}
}