/*******************************************************************************
* Copyright (c) 2012, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.orion.internal.server.servlets.useradmin;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.orion.server.core.LogHelper;
import org.eclipse.orion.server.core.OrionConfiguration;
import org.eclipse.orion.server.core.ProtocolConstants;
import org.eclipse.orion.server.core.ServerConstants;
import org.eclipse.orion.server.core.ServerStatus;
import org.eclipse.orion.server.core.UserEmailUtil;
import org.eclipse.orion.server.core.metastore.UserInfo;
import org.eclipse.orion.server.core.users.UserConstants;
import org.eclipse.orion.server.servlets.OrionServlet;
import org.json.JSONException;
import org.json.JSONObject;
public class EmailConfirmationServlet extends OrionServlet {
private static final long serialVersionUID = 2029138177545673411L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
traceRequest(req);
String[] userPathInfoParts = req.getPathInfo().split("\\/", 2);
// handle calls to /users/[userId]
String userId = userPathInfoParts[1];
UserInfo userInfo = null;
try {
userInfo = OrionConfiguration.getMetaStore().readUserByProperty(UserConstants.USER_NAME, userId, false, false);
} catch (CoreException e) {
LogHelper.log(e);
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "User " + userId + " not found.");
return;
}
if (userInfo == null) {
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "User " + userId + " not found.");
return;
}
if (req.getParameter(UserConstants.PASSWORD_RESET_ID) != null) {
resetPassword(userInfo, req, resp);
} else {
confirmEmail(userInfo, req, resp);
}
}
private void resetPassword(UserInfo userInfo, HttpServletRequest req, HttpServletResponse resp) throws IOException {
if (userInfo.getProperty(UserConstants.PASSWORD_RESET_ID) == null || "".equals(userInfo.getProperty(UserConstants.PASSWORD_RESET_ID))) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST,
"You have not requested to reset your password or this password reset request was already completed");
return;
}
if (!userInfo.getProperty(UserConstants.PASSWORD_RESET_ID).equals(req.getParameter(UserConstants.PASSWORD_RESET_ID))) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "This password reset request is out of date");
return;
}
String newPass = getRandomPassword();
userInfo.setProperty(UserConstants.PASSWORD, newPass);
userInfo.setProperty(UserConstants.PASSWORD_RESET_ID, null);
try {
UserEmailUtil.getUtil().sendPasswordResetEmail(userInfo);
} catch (Exception e) {
LogHelper.log(e);
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Your password could not be changed, because confirmation email could not be sent. To reset your password contact your administrator.");
return;
}
try {
OrionConfiguration.getMetaStore().updateUser(userInfo);
} catch (Exception e) {
LogHelper.log(e);
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
"Your password could not be changed. To reset your password contact your administrator.");
return;
}
resp.setContentType(ProtocolConstants.CONTENT_TYPE_HTML);
resp.getWriter().write(
"<html><body><p>Your password has been successfully reset. Your new password has been sent to the email address associated with your account.</p></body></html>");
return;
}
private void confirmEmail(UserInfo userInfo, HttpServletRequest req, HttpServletResponse resp) throws IOException {
if (userInfo.getProperty(UserConstants.EMAIL_CONFIRMATION_ID) == null) {
resp.setContentType(ProtocolConstants.CONTENT_TYPE_HTML);
resp.getWriter().write("<html><body><p>Your email address has already been confirmed. Thank you!</p></body></html>");
return;
}
if (req.getParameter(UserConstants.EMAIL_CONFIRMATION_ID) == null
|| !req.getParameter(UserConstants.EMAIL_CONFIRMATION_ID).equals(userInfo.getProperty(UserConstants.EMAIL_CONFIRMATION_ID))) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Email could not be confirmed.");
return;
}
try {
userInfo.setProperty(UserConstants.EMAIL_CONFIRMATION_ID, null);
userInfo.setProperty(UserConstants.BLOCKED, null);
OrionConfiguration.getMetaStore().updateUser(userInfo);
} catch (CoreException e) {
LogHelper.log(e);
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
return;
}
resp.setContentType(ProtocolConstants.CONTENT_TYPE_HTML);
StringBuffer host = new StringBuffer();
String scheme = req.getScheme();
host.append(scheme);
host.append(":////");
String servername = req.getServerName();
host.append(servername);
host.append(":");
int port = req.getServerPort();
host.append(port);
resp.getWriter().write("<html><body><p>Your email address has been confirmed. Thank you! <a href=\"" + host
+ "\">Click here</a> to continue and login to your account.</p></body></html>");
return;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
traceRequest(req);
String[] userPathInfoParts = req.getPathInfo() == null ? new String[0] : req.getPathInfo().split("\\/", 2);
if (userPathInfoParts.length > 1 && userPathInfoParts[1] != null && "cansendemails".equalsIgnoreCase(userPathInfoParts[1])) {
JSONObject jsonResp = new JSONObject();
try {
jsonResp.put("EmailConfigured", UserEmailUtil.getUtil().isEmailConfigured());
writeJSONResponse(req, resp, jsonResp);
} catch (JSONException e) {
// this should never happen
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
}
return;
}
String userEmail = null;
String userName = null;
try {
JSONObject json = OrionServlet.readJSONRequest(req);
if (json.has(UserConstants.EMAIL)) {
userEmail = json.getString(UserConstants.EMAIL);
}
if (json.has(UserConstants.USER_NAME)) {
userName = json.getString(UserConstants.USER_NAME);
}
} catch (JSONException e) {
getStatusHandler().handleRequest(req, resp, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, "Could not parse json request", e));
return;
}
List<UserInfo> users = new ArrayList<UserInfo>();
if (userName != null && userName.trim().length() > 0) {
// reset using login
UserInfo userInfo = null;
try {
userInfo = OrionConfiguration.getMetaStore().readUserByProperty(UserConstants.USER_NAME, userName.trim(), false, false);
} catch (CoreException e) {
LogHelper.log(e);
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
return;
}
if (userInfo == null) {
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "User " + userName + " not found.");
return;
}
if (userEmail != null && userEmail.trim().length() > 0) {
if (!isEmailConfirmed(userInfo)) {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "User " + userName + " email has not been yet confirmed."
+ " Please follow the instructions from the confirmation email in your inbox and then request a password reset again.");
return;
}
if (!userEmail.equals(userInfo.getProperty(UserConstants.EMAIL))) {
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "User " + userName + " with email " + userEmail + " does not exist.");
return;
}
}
users.add(userInfo);
} else if (userEmail != null && userEmail.trim().length() > 0) {
// reset using email address
UserInfo userInfo = null;
try {
userInfo = OrionConfiguration.getMetaStore().readUserByProperty(UserConstants.EMAIL, userEmail.trim().toLowerCase(), false, false);
} catch (CoreException e) {
LogHelper.log(e);
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
return;
}
if (userInfo != null && isEmailConfirmed(userInfo)) {
users.add(userInfo);
}
if (users.size() == 0) {
if (userInfo == null) {
resp.sendError(HttpServletResponse.SC_NOT_FOUND, "User with email " + userEmail + " not found.");
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Email " + userName + " has not been yet confirmed."
+ " Please follow the instructions from the confirmation email in your inbox and then request a password reset again.");
}
return;
}
}
MultiStatus multiStatus = new MultiStatus(ServerConstants.PI_SERVER_CORE, IStatus.OK, null, null);
req.getRequestURI();
final URI baseURI = URI.create(req.getRequestURL().toString());
for (UserInfo userInfo : users)
multiStatus.add(sendPasswordResetConfirmation(userInfo, baseURI));
if (!multiStatus.isOK()) {
for (int i = 0; i < multiStatus.getChildren().length; i++) {
IStatus status = multiStatus.getChildren()[i];
if (status.isOK()) {
continue;
}
getStatusHandler().handleRequest(req, resp, status);
return;
}
}
getStatusHandler().handleRequest(req, resp,
new ServerStatus(IStatus.INFO, HttpServletResponse.SC_OK, "Confirmation email has been sent to " + userEmail, null));
}
private IStatus sendPasswordResetConfirmation(UserInfo userInfo, URI baseUri) {
if (userInfo.getProperty(UserConstants.EMAIL) == null || userInfo.getProperty(UserConstants.EMAIL).length() == 0) {
return new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST,
"User " + userInfo.getUniqueId() + " doesn't have its email set. Contact administrator to reset your password.", null);
}
if (!isEmailConfirmed(userInfo)) {
return new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, "Your email has not been yet confirmed."
+ " Please follow the instructions from the confirmation email in your inbox and then request a password reset again.", null);
}
try {
userInfo.setProperty(UserConstants.PASSWORD_RESET_ID, getUniqueEmailConfirmationId());
OrionConfiguration.getMetaStore().updateUser(userInfo);
} catch (CoreException e) {
LogHelper.log(e);
return new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage(), e);
}
try {
UserEmailUtil.getUtil().sendResetPasswordConfirmation(baseUri, userInfo);
return new ServerStatus(IStatus.INFO, HttpServletResponse.SC_OK, "Confirmation email has been sent.", null);
} catch (Exception e) {
LogHelper.log(e);
return new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, "Could not send confirmation email.", null);
}
}
/**
* Generates random string that may be used as auto-generated password after user reset.
*
* @return a random string.
*/
private String getRandomPassword() {
return getRandomString(5, 25);
}
private String getRandomString(int lo, int hi) {
int n = getRandomNumber(lo, hi);
byte b[] = new byte[n];
for (int i = 0; i < n; i++)
b[i] = (byte) getRandomNumber('1', 'Z');
return new String(b);
}
private int getRandomNumber(int lo, int hi) {
Random rn = new Random();
int n = hi - lo + 1;
int i = rn.nextInt(n);
if (i < 0)
i = -i;
return lo + i;
}
private boolean isEmailConfirmed(UserInfo userInfo) {
String email = userInfo.getProperty(UserConstants.EMAIL);
return (email != null && email.length() > 0) ? userInfo.getProperty(UserConstants.EMAIL_CONFIRMATION_ID) == null : false;
}
private static String getUniqueEmailConfirmationId() {
return System.currentTimeMillis() + "-" + Math.random();
}
}