package org.cloudfoundry.identity.uaa.login;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudfoundry.identity.uaa.error.UaaException;
import org.cloudfoundry.identity.uaa.login.AccountCreationService.ExistingUserResponse;
import org.cloudfoundry.identity.uaa.message.PasswordChangeRequest;
import org.cloudfoundry.identity.uaa.scim.ScimUser;
import org.codehaus.jackson.map.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.stereotype.Service;
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.context.Context;
import org.thymeleaf.spring4.SpringTemplateEngine;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Service
public class EmailInvitationsService implements InvitationsService {
private final Log logger = LogFactory.getLog(getClass());
public static final String INVITATION_REDIRECT_URL = "invitation_redirect_url";
public static final int INVITATION_EXPIRY_DAYS = 365;
private final SpringTemplateEngine templateEngine;
private final MessageService messageService;
private final String uaaBaseUrl;
private String brand;
public EmailInvitationsService(SpringTemplateEngine templateEngine, MessageService messageService, String brand, String uaaBaseUrl) {
this.templateEngine = templateEngine;
this.messageService = messageService;
this.brand = brand;
this.uaaBaseUrl = uaaBaseUrl;
}
public void setBrand(String brand) {
this.brand = brand;
}
@Autowired
private AccountCreationService accountCreationService;
@Autowired
private ExpiringCodeService expiringCodeService;
@Autowired
private RestTemplate authorizationTemplate;
private void sendInvitationEmail(String email, String userId, String currentUser, String code) {
String subject = getSubjectText();
try {
String htmlContent = getEmailHtml(currentUser, code);
messageService.sendMessage(userId, email, MessageType.INVITATION, subject, htmlContent);
} catch (RestClientException e) {
logger.info("Exception raised while creating invitation email from " + email, e);
}
}
private String getSubjectText() {
return brand.equals("pivotal") ? "Invitation to join Pivotal" : "Invitation to join Cloud Foundry";
}
private String getEmailHtml(String currentUser, String code) {
String accountsUrl = ServletUriComponentsBuilder.fromCurrentContextPath().path("/invitations/accept").build().toUriString();
final Context ctx = new Context();
ctx.setVariable("serviceName", brand.equals("pivotal") ? "Pivotal" : "Cloud Foundry");
ctx.setVariable("code", code);
ctx.setVariable("currentUser", currentUser);
ctx.setVariable("accountsUrl", accountsUrl);
return templateEngine.process("invite", ctx);
}
@Override
public void inviteUser(String email, String currentUser) {
try {
ScimUser user = accountCreationService.createUser(email, null);
Map<String,String> data = new HashMap<>();
data.put("user_id", user.getId());
data.put("email", email);
String code = expiringCodeService.generateCode(data, INVITATION_EXPIRY_DAYS, TimeUnit.DAYS);
sendInvitationEmail(email, user.getId(), currentUser, code);
} catch (HttpClientErrorException e) {
String uaaResponse = e.getResponseBodyAsString();
try {
ExistingUserResponse existingUserResponse = new ObjectMapper().readValue(uaaResponse, ExistingUserResponse.class);
if (existingUserResponse.getVerified()) {
throw new UaaException(e.getStatusText(), e.getStatusCode().value());
}
Map<String,String> data = new HashMap<>();
data.put("user_id", existingUserResponse.getUserId());
data.put("email", email);
String code = expiringCodeService.generateCode(data, INVITATION_EXPIRY_DAYS, TimeUnit.DAYS);
sendInvitationEmail(email, existingUserResponse.getUserId(), currentUser, code);
} catch (IOException ioe) {
logger.warn("couldn't invite user",ioe);
}
} catch (IOException e) {
logger.warn("couldn't invite user",e);
}
}
@Override
public String acceptInvitation(String userId, String email, String password, String clientId) {
authorizationTemplate.getForEntity(uaaBaseUrl + "/Users/" + userId + "/verify",Object.class);
PasswordChangeRequest request = new PasswordChangeRequest();
request.setPassword(password);
authorizationTemplate.put(uaaBaseUrl + "/Users/" + userId + "/password", request);
String redirectLocation = null;
if (clientId != null && !clientId.equals("")) {
ClientDetails clientDetails = authorizationTemplate.getForObject(uaaBaseUrl + "/oauth/clients/" + clientId, BaseClientDetails.class);
redirectLocation = (String) clientDetails.getAdditionalInformation().get(INVITATION_REDIRECT_URL);
}
return redirectLocation;
}
}