package org.cloudfoundry.identity.uaa.login;
import org.cloudfoundry.identity.uaa.error.UaaException;
import org.cloudfoundry.identity.uaa.login.test.ThymeleafConfig;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpStatus;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.thymeleaf.spring4.SpringTemplateEngine;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.contains;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isNull;
import static org.springframework.http.HttpMethod.POST;
import static org.springframework.http.MediaType.APPLICATION_JSON;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.content;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.jsonPath;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.method;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withBadRequest;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus;
import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ThymeleafConfig.class)
public class EmailChangeEmailServiceTest {
private EmailChangeEmailService emailChangeEmailService;
private MockRestServiceServer mockUaaServer;
private MessageService messageService;
@Autowired
@Qualifier("mailTemplateEngine")
SpringTemplateEngine templateEngine;
private RestTemplate uaaTemplate;
@Before
public void setUp() throws Exception {
uaaTemplate = new RestTemplate();
mockUaaServer = MockRestServiceServer.createServer(uaaTemplate);
messageService = Mockito.mock(EmailService.class);
emailChangeEmailService = new EmailChangeEmailService(templateEngine, messageService, uaaTemplate, "http://uaa.example.com/uaa", "pivotal");
MockHttpServletRequest request = new MockHttpServletRequest();
request.setProtocol("http");
request.setContextPath("/login");
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));
}
@Test
public void beginEmailChange() throws Exception {
setUpForSuccess();
emailChangeEmailService.beginEmailChange("user-001", "user@example.com", "new@example.com", "app");
mockUaaServer.verify();
Mockito.verify(messageService).sendMessage((String) isNull(),
eq("new@example.com"),
eq(MessageType.CHANGE_EMAIL),
eq("Email change verification"),
contains("<a href=\"http://localhost/login/verify_email?code=the_secret_code\">Verify your email</a>")
);
}
@Test
public void testBeginEmailChangeWithOssBrand() throws Exception {
emailChangeEmailService = new EmailChangeEmailService(templateEngine, messageService, uaaTemplate, "http://uaa.example.com/uaa", "oss");
setUpForSuccess();
emailChangeEmailService.beginEmailChange("user-001", "user@example.com", "new@example.com", "app");
mockUaaServer.verify();
ArgumentCaptor<String> emailBodyArgument = ArgumentCaptor.forClass(String.class);
Mockito.verify(messageService).sendMessage((String) isNull(),
eq("new@example.com"),
eq(MessageType.CHANGE_EMAIL),
eq("Email change verification"),
emailBodyArgument.capture()
);
String emailBody = emailBodyArgument.getValue();
assertThat(emailBody, containsString("<a href=\"http://localhost/login/verify_email?code=the_secret_code\">Verify your email</a>"));
assertThat(emailBody, containsString("an account"));
assertThat(emailBody, containsString("Cloud Foundry"));
assertThat(emailBody, not(containsString("a Pivotal ID")));
}
@Test(expected = UaaException.class)
public void beginEmailChangeWithUsernameConflict() throws Exception {
mockUaaServer.expect(requestTo("http://uaa.example.com/uaa/email_verifications"))
.andExpect(method(POST))
.andExpect(jsonPath("$.userId").value("user-001"))
.andExpect(jsonPath("$.email").value("new@example.com"))
.andRespond(withStatus(HttpStatus.CONFLICT));
emailChangeEmailService.beginEmailChange("user-001", "user@example.com", "new@example.com", null);
}
@Test
public void testCompleteVerification() throws Exception {
mockUaaServer.expect(requestTo("http://uaa.example.com/uaa/email_changes"))
.andExpect(method(POST))
.andExpect(content().string("the_secret_code"))
.andRespond(withSuccess("{" +
" \"user_id\":\"user-001\"," +
" \"username\":\"new@example.com\"," +
" \"email\": \"new@example.com\" " +
"}", APPLICATION_JSON));
emailChangeEmailService.completeVerification("the_secret_code");
mockUaaServer.verify();
}
@Test(expected = UaaException.class)
public void testCompleteVerificationWithInvalidCode() throws Exception {
mockUaaServer.expect(requestTo("http://uaa.example.com/uaa/email_changes"))
.andExpect(method(POST))
.andExpect(content().string("the_secret_code"))
.andRespond(withBadRequest());
emailChangeEmailService.completeVerification("the_secret_code");
mockUaaServer.verify();
}
private void setUpForSuccess() {
mockUaaServer.expect(requestTo("http://uaa.example.com/uaa/email_verifications"))
.andExpect(method(POST))
.andExpect(jsonPath("$.userId").value("user-001"))
.andExpect(jsonPath("$.email").value("new@example.com"))
.andExpect(jsonPath("$.client_id").value("app"))
.andRespond(withSuccess("the_secret_code", APPLICATION_JSON));
}
}