/*******************************************************************************
* Cloud Foundry
* Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
*
* This product is licensed to you under the Apache License, Version 2.0 (the "License").
* You may not use this product except in compliance with the License.
*
* This product includes a number of subcomponents with
* separate copyright notices and license terms. Your use of these
* subcomponents is subject to the terms and conditions of the
* subcomponent's license, as noted in the LICENSE file.
*******************************************************************************/
package org.cloudfoundry.identity.uaa.login;
import org.cloudfoundry.identity.uaa.error.UaaException;
import org.cloudfoundry.identity.uaa.login.test.ThymeleafConfig;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.client.ClientHttpRequest;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.mock.http.client.MockClientHttpResponse;
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.test.web.client.ResponseCreator;
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 java.io.IOException;
import java.util.Map;
import static org.mockito.Matchers.contains;
import static org.mockito.Matchers.eq;
import static org.springframework.http.HttpMethod.POST;
import static org.springframework.http.HttpStatus.CONFLICT;
import static org.springframework.http.MediaType.APPLICATION_JSON;
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.withSuccess;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ThymeleafConfig.class)
public class EmailResetPasswordServiceTests {
private EmailResetPasswordService emailResetPasswordService;
private MockRestServiceServer mockUaaServer;
private MessageService messageService;
@Autowired
@Qualifier("mailTemplateEngine")
SpringTemplateEngine templateEngine;
@Before
public void setUp() throws Exception {
RestTemplate uaaTemplate = new RestTemplate();
mockUaaServer = MockRestServiceServer.createServer(uaaTemplate);
messageService = Mockito.mock(EmailService.class);
emailResetPasswordService = new EmailResetPasswordService(templateEngine, messageService, uaaTemplate, "http://uaa.example.com/uaa", "pivotal");
}
@Test
public void testForgotPasswordWhenAResetCodeIsReturnedByTheUaa() throws Exception {
mockUaaServer.expect(requestTo("http://uaa.example.com/uaa/password_resets"))
.andExpect(method(POST))
.andRespond(withSuccess("{\"code\":\"the_secret_code\",\"user_id\":\"user-id-001\"}", APPLICATION_JSON));
MockHttpServletRequest request = new MockHttpServletRequest();
request.setProtocol("http");
request.setContextPath("/login");
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));
emailResetPasswordService.forgotPassword("user@example.com");
mockUaaServer.verify();
Mockito.verify(messageService).sendMessage(eq("user-id-001"),
eq("user@example.com"),
eq(MessageType.PASSWORD_RESET),
eq("Pivotal account password reset request"),
contains("<a href=\"http://localhost/login/reset_password?code=the_secret_code&email=user%40example.com\">Reset your password</a>")
);
}
@Test
public void testForgotPasswordWhenConflictIsReturnedByTheUaa() throws Exception {
mockUaaServer.expect(requestTo("http://uaa.example.com/uaa/password_resets"))
.andExpect(method(POST))
.andRespond(new ResponseCreator() {
@Override
public ClientHttpResponse createResponse(ClientHttpRequest request) throws IOException {
return new MockClientHttpResponse("{\"user_id\":\"user-id-001\"}".getBytes(), CONFLICT);
}
});
MockHttpServletRequest request = new MockHttpServletRequest();
request.setProtocol("http");
request.setContextPath("/login");
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));
emailResetPasswordService.forgotPassword("user@example.com");
mockUaaServer.verify();
Mockito.verify(messageService).sendMessage(eq("user-id-001"),
eq("user@example.com"),
eq(MessageType.PASSWORD_RESET),
eq("Pivotal account password reset request"),
contains("Your account credentials for localhost are managed by an external service. Please contact your administrator for password recovery requests.")
);
}
@Test
public void testForgotPasswordWhenTheCodeIsDenied() throws Exception {
mockUaaServer.expect(requestTo("http://uaa.example.com/uaa/password_resets"))
.andExpect(method(POST))
.andRespond(withBadRequest());
emailResetPasswordService.forgotPassword("user@example.com");
mockUaaServer.verify();
Mockito.verifyZeroInteractions(messageService);
}
@Test
public void testResetPassword() throws Exception {
mockUaaServer.expect(requestTo("http://uaa.example.com/uaa/password_change"))
.andExpect(method(POST))
.andExpect(jsonPath("$.code").value("secret_code"))
.andExpect(jsonPath("$.new_password").value("new_secret"))
.andRespond(withSuccess("{" +
" \"user_id\":\"usermans-id\"," +
" \"username\":\"userman\"" +
"}", APPLICATION_JSON));
Map<String,String> userInfo = emailResetPasswordService.resetPassword("secret_code", "new_secret");
mockUaaServer.verify();
Assert.assertThat(userInfo, Matchers.hasEntry("user_id", "usermans-id"));
Assert.assertThat(userInfo, Matchers.hasEntry("username", "userman"));
}
@Test(expected = UaaException.class)
public void testResetPasswordWhenTheCodeIsDenied() throws Exception {
mockUaaServer.expect(requestTo("http://uaa.example.com/uaa/password_change"))
.andExpect(method(POST))
.andRespond(withBadRequest());
emailResetPasswordService.resetPassword("b4d_k0d3z", "new_password");
mockUaaServer.verify();
}
}