/*******************************************************************************
* 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.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudfoundry.identity.uaa.authentication.Origin;
import org.cloudfoundry.identity.uaa.error.UaaException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class EmailResetPasswordService implements ResetPasswordService {
private final Log logger = LogFactory.getLog(getClass());
private final TemplateEngine templateEngine;
private final MessageService messageService;
private final RestTemplate uaaTemplate;
private final String uaaBaseUrl;
private final String brand;
public EmailResetPasswordService(TemplateEngine templateEngine, MessageService messageService, RestTemplate uaaTemplate, String uaaBaseUrl, String brand) {
this.templateEngine = templateEngine;
this.messageService = messageService;
this.uaaTemplate = uaaTemplate;
this.uaaBaseUrl = uaaBaseUrl;
this.brand = brand;
}
@Override
public void forgotPassword(String email) {
String subject = getSubjectText();
String htmlContent = null;
String userId = null;
try {
ResponseEntity<Map<String,String>> response = uaaTemplate.exchange(uaaBaseUrl + "/password_resets", HttpMethod.POST, new HttpEntity<>(email), new ParameterizedTypeReference<Map<String, String>>() {
});
htmlContent = getCodeSentEmailHtml(response.getBody().get("code"), email);
userId = response.getBody().get("user_id");
} catch (HttpClientErrorException e) {
if (e.getStatusCode() == HttpStatus.CONFLICT) {
htmlContent = getResetUnavailableEmailHtml(email);
try {
Map<String, String> body = new ObjectMapper().readValue(e.getResponseBodyAsString(), new TypeReference<Map<String, String>>() {
});
userId = body.get("user_id");
} catch (IOException ioe) {
logger.error("Bad response from UAA", ioe);
}
} else {
logger.info("Exception raised while creating password reset for " + email, e);
}
} catch (RestClientException e) {
logger.error("Exception raised while creating password reset for " + email, e);
}
if (htmlContent != null && userId != null) {
messageService.sendMessage(userId, email, MessageType.PASSWORD_RESET, subject, htmlContent);
}
}
private String getSubjectText() {
return brand.equals("pivotal") ? "Pivotal account password reset request" : "Account password reset request";
}
@Override
public Map<String, String> resetPassword(String code, String newPassword) {
Map<String, String> uriVariables = new HashMap<>();
uriVariables.put("baseUrl", uaaBaseUrl);
Map<String, String> formData = new HashMap<>();
formData.put("code", code);
formData.put("new_password", newPassword);
try {
ResponseEntity<Map<String, String>> responseEntity = uaaTemplate.exchange(
"{baseUrl}/password_change",
HttpMethod.POST,
new HttpEntity<>(formData),
new ParameterizedTypeReference<Map<String, String>>() {
},
uriVariables
);
return responseEntity.getBody();
} catch (RestClientException e) {
throw new UaaException(e.getMessage());
}
}
private String getCodeSentEmailHtml(String code, String email) {
String resetUrl = ServletUriComponentsBuilder.fromCurrentContextPath().path("/reset_password").build().toUriString();
final Context ctx = new Context();
ctx.setVariable("serviceName", brand.equals("pivotal") ? "Pivotal " : "");
ctx.setVariable("code", code);
ctx.setVariable("email", email);
ctx.setVariable("resetUrl", resetUrl);
return templateEngine.process("reset_password", ctx);
}
private String getResetUnavailableEmailHtml(String email) {
String hostname = ServletUriComponentsBuilder.fromCurrentContextPath().build().getHost();
final Context ctx = new Context();
ctx.setVariable("serviceName", brand.equals("pivotal") ? "Pivotal " : "");
ctx.setVariable("email", email);
ctx.setVariable("hostname", hostname);
return templateEngine.process("reset_password_unavailable", ctx);
}
}