/******************************************************************************* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. *******************************************************************************/ package org.apache.ofbiz.securityext.login; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.apache.commons.lang.RandomStringUtils; import org.apache.ofbiz.base.crypto.HashCrypt; import org.apache.ofbiz.base.util.Debug; import org.apache.ofbiz.base.util.GeneralException; import org.apache.ofbiz.base.util.UtilFormatOut; import org.apache.ofbiz.base.util.UtilHttp; import org.apache.ofbiz.base.util.UtilMisc; import org.apache.ofbiz.base.util.UtilProperties; import org.apache.ofbiz.base.util.UtilValidate; import org.apache.ofbiz.base.util.string.FlexibleStringExpander; import org.apache.ofbiz.common.login.LoginServices; import org.apache.ofbiz.entity.Delegator; import org.apache.ofbiz.entity.GenericDelegator; import org.apache.ofbiz.entity.GenericEntityException; import org.apache.ofbiz.entity.GenericValue; import org.apache.ofbiz.entity.model.ModelField.EncryptMethod; import org.apache.ofbiz.entity.util.EntityCrypto; import org.apache.ofbiz.entity.util.EntityQuery; import org.apache.ofbiz.entity.util.EntityUtilProperties; import org.apache.ofbiz.party.contact.ContactHelper; import org.apache.ofbiz.product.product.ProductEvents; import org.apache.ofbiz.product.store.ProductStoreWorker; import org.apache.ofbiz.service.GenericServiceException; import org.apache.ofbiz.service.LocalDispatcher; import org.apache.ofbiz.service.ModelService; import org.apache.ofbiz.webapp.control.LoginWorker; /** * LoginEvents - Events for UserLogin and Security handling. */ public class LoginEvents { public static final String module = LoginEvents.class.getName(); public static final String resource = "SecurityextUiLabels"; public static final String usernameCookieName = "OFBiz.Username"; private static final String keyValue = UtilProperties.getPropertyValue(LoginWorker.securityProperties, "login.secret_key_string"); /** * Save USERNAME and PASSWORD for use by auth pages even if we start in non-auth pages. * * @param request The HTTP request object for the current JSP or Servlet request. * @param response The HTTP response object for the current JSP or Servlet request. * @return String */ public static String saveEntryParams(HttpServletRequest request, HttpServletResponse response) { GenericValue userLogin = (GenericValue) request.getSession().getAttribute("userLogin"); HttpSession session = request.getSession(); Delegator delegator = (Delegator) request.getAttribute("delegator"); // save entry login parameters if we don't have a valid login object if (userLogin == null) { String username = request.getParameter("USERNAME"); String password = request.getParameter("PASSWORD"); if ((username != null) && ("true".equalsIgnoreCase(EntityUtilProperties.getPropertyValue("security", "username.lowercase", delegator)))) { username = username.toLowerCase(); } if ((password != null) && ("true".equalsIgnoreCase(EntityUtilProperties.getPropertyValue("security", "password.lowercase", delegator)))) { password = password.toLowerCase(); } // save parameters into the session - so they can be used later, if needed if (username != null) session.setAttribute("USERNAME", username); if (password != null) session.setAttribute("PASSWORD", password); } else { // if the login object is valid, remove attributes session.removeAttribute("USERNAME"); session.removeAttribute("PASSWORD"); } return "success"; } /** * The user forgot his/her password. This will call showPasswordHint, emailPassword or simply returns "success" in case * no operation has been specified. * * @param request The HTTPRequest object for the current request * @param response The HTTPResponse object for the current request * @return String specifying the exit status of this event */ public static String forgotPassword(HttpServletRequest request, HttpServletResponse response) { GenericDelegator delegator = (GenericDelegator) request.getAttribute("delegator"); String questionEnumId = request.getParameter("securityQuestion"); String securityAnswer = request.getParameter("securityAnswer"); String userLoginId = request.getParameter("USERNAME"); String errMsg = null; try { GenericValue userLoginSecurityQuestion = delegator.findOne("UserLoginSecurityQuestion", UtilMisc.toMap("questionEnumId", questionEnumId, "userLoginId", userLoginId), true); if (userLoginSecurityQuestion != null) { if (UtilValidate.isEmpty(securityAnswer)) { errMsg = UtilProperties.getMessage(resource, "loginservices.security_answer_empty", UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } String ulSecurityAnswer = userLoginSecurityQuestion.getString("securityAnswer"); if (UtilValidate.isNotEmpty(ulSecurityAnswer) && !securityAnswer.equalsIgnoreCase(ulSecurityAnswer)) { errMsg = UtilProperties.getMessage(resource, "loginservices.security_answer_not_match", UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } } } catch (GenericEntityException e) { errMsg = UtilProperties.getMessage(resource, "loginevents.problem_getting_security_question_record", UtilHttp.getLocale(request)); Debug.logError(e, errMsg, module); } if ((UtilValidate.isNotEmpty(request.getParameter("GET_PASSWORD_HINT"))) || (UtilValidate.isNotEmpty(request.getParameter("GET_PASSWORD_HINT.x")))) { return showPasswordHint(request, response); } else if ((UtilValidate.isNotEmpty(request.getParameter("EMAIL_PASSWORD"))) || (UtilValidate.isNotEmpty(request.getParameter("EMAIL_PASSWORD.x")))) { return emailPassword(request, response); } else { return "success"; } } /** Show the password hint for the userLoginId specified in the request object. *@param request The HTTPRequest object for the current request *@param response The HTTPResponse object for the current request *@return String specifying the exit status of this event */ public static String showPasswordHint(HttpServletRequest request, HttpServletResponse response) { Delegator delegator = (Delegator) request.getAttribute("delegator"); String userLoginId = request.getParameter("USERNAME"); String errMsg = null; if ((userLoginId != null) && ("true".equals(EntityUtilProperties.getPropertyValue("security", "username.lowercase", delegator)))) { userLoginId = userLoginId.toLowerCase(); } if (UtilValidate.isEmpty(userLoginId)) { // the password was incomplete errMsg = UtilProperties.getMessage(resource, "loginevents.username_was_empty_reenter", UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } GenericValue supposedUserLogin = null; try { supposedUserLogin = EntityQuery.use(delegator).from("UserLogin").where("userLoginId", userLoginId).queryOne(); } catch (GenericEntityException gee) { Debug.logWarning(gee, "", module); } if (supposedUserLogin == null) { // the Username was not found errMsg = UtilProperties.getMessage(resource, "loginevents.username_not_found_reenter", UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } String passwordHint = supposedUserLogin.getString("passwordHint"); if (UtilValidate.isEmpty(passwordHint)) { // the Username was not found errMsg = UtilProperties.getMessage(resource, "loginevents.no_password_hint_specified_try_password_emailed", UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } Map<String, String> messageMap = UtilMisc.toMap("passwordHint", passwordHint); errMsg = UtilProperties.getMessage(resource, "loginevents.password_hint_is", messageMap, UtilHttp.getLocale(request)); request.setAttribute("_EVENT_MESSAGE_", errMsg); return "success"; } /** * Email the password for the userLoginId specified in the request object. * * @param request The HTTPRequest object for the current request * @param response The HTTPResponse object for the current request * @return String specifying the exit status of this event */ public static String emailPassword(HttpServletRequest request, HttpServletResponse response) { String defaultScreenLocation = "component://securityext/widget/EmailSecurityScreens.xml#PasswordEmail"; Delegator delegator = (Delegator) request.getAttribute("delegator"); LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher"); String productStoreId = ProductStoreWorker.getProductStoreId(request); String errMsg = null; boolean useEncryption = "true".equals(EntityUtilProperties.getPropertyValue("security", "password.encrypt", delegator)); String userLoginId = request.getParameter("USERNAME"); if ((userLoginId != null) && ("true".equals(EntityUtilProperties.getPropertyValue("security", "username.lowercase", delegator)))) { userLoginId = userLoginId.toLowerCase(); } if (UtilValidate.isEmpty(userLoginId)) { // the password was incomplete errMsg = UtilProperties.getMessage(resource, "loginevents.username_was_empty_reenter", UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } GenericValue supposedUserLogin = null; String passwordToSend = null; String autoPassword = null; try { supposedUserLogin = EntityQuery.use(delegator).from("UserLogin").where("userLoginId", userLoginId).queryOne(); if (supposedUserLogin == null) { // the Username was not found errMsg = UtilProperties.getMessage(resource, "loginevents.username_not_found_reenter", UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } if (useEncryption) { // password encrypted, can't send, generate new password and email to user passwordToSend = RandomStringUtils.randomAlphanumeric(EntityUtilProperties.getPropertyAsInteger("security", "password.length.min", 5).intValue()); if ("true".equals(EntityUtilProperties.getPropertyValue("security", "password.lowercase", delegator))){ passwordToSend=passwordToSend.toLowerCase(); } autoPassword = RandomStringUtils.randomAlphanumeric(EntityUtilProperties.getPropertyAsInteger("security", "password.length.min", 5).intValue()); EntityCrypto entityCrypto = new EntityCrypto(delegator,null); try { passwordToSend = entityCrypto.encrypt(keyValue, EncryptMethod.TRUE, (Object) autoPassword); } catch (GeneralException e) { Debug.logWarning(e, "Problem in encryption", module); } supposedUserLogin.set("currentPassword", HashCrypt.cryptUTF8(LoginServices.getHashType(), null, autoPassword)); supposedUserLogin.set("passwordHint", "Auto-Generated Password"); if ("true".equals(EntityUtilProperties.getPropertyValue("security", "password.email_password.require_password_change", delegator))){ supposedUserLogin.set("requirePasswordChange", "Y"); } } else { passwordToSend = supposedUserLogin.getString("currentPassword"); } /* Its a Base64 string, it can contain + and this + will be converted to space after decoding the url. For example: passwordToSend "DGb1s2wgUQmwOBK9FK+fvQ==" will be converted to "DGb1s2wgUQmwOBK9FK fvQ==" So to fix it, done Url encoding of passwordToSend. */ passwordToSend = URLEncoder.encode(passwordToSend, "UTF-8"); } catch (GenericEntityException | UnsupportedEncodingException e) { Debug.logWarning(e, "", module); Map<String, String> messageMap = UtilMisc.toMap("errorMessage", e.toString()); errMsg = UtilProperties.getMessage(resource, "loginevents.error_accessing_password", messageMap, UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } StringBuilder emails = new StringBuilder(); GenericValue party = null; try { party = supposedUserLogin.getRelatedOne("Party", false); } catch (GenericEntityException e) { Debug.logWarning(e, "", module); party = null; } if (party != null) { Iterator<GenericValue> emailIter = UtilMisc.toIterator(ContactHelper.getContactMechByPurpose(party, "PRIMARY_EMAIL", false)); while (emailIter != null && emailIter.hasNext()) { GenericValue email = emailIter.next(); emails.append(emails.length() > 0 ? "," : "").append(email.getString("infoString")); } } if (UtilValidate.isEmpty(emails.toString())) { // the Username was not found errMsg = UtilProperties.getMessage(resource, "loginevents.no_primary_email_address_set_contact_customer_service", UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } // get the ProductStore email settings GenericValue productStoreEmail = null; try { productStoreEmail = EntityQuery.use(delegator).from("ProductStoreEmailSetting").where("productStoreId", productStoreId, "emailType", "PRDS_PWD_RETRIEVE").queryOne(); } catch (GenericEntityException e) { Debug.logError(e, "Problem getting ProductStoreEmailSetting", module); } String bodyScreenLocation = null; if (productStoreEmail != null) { bodyScreenLocation = productStoreEmail.getString("bodyScreenLocation"); } if (UtilValidate.isEmpty(bodyScreenLocation)) { bodyScreenLocation = defaultScreenLocation; } // set the needed variables in new context Map<String, Object> bodyParameters = new HashMap<String, Object>(); bodyParameters.put("useEncryption", Boolean.valueOf(useEncryption)); bodyParameters.put("password", UtilFormatOut.checkNull(passwordToSend)); bodyParameters.put("locale", UtilHttp.getLocale(request)); bodyParameters.put("userLogin", supposedUserLogin); bodyParameters.put("productStoreId", productStoreId); Map<String, Object> serviceContext = new HashMap<String, Object>(); serviceContext.put("bodyScreenUri", bodyScreenLocation); serviceContext.put("bodyParameters", bodyParameters); if (productStoreEmail != null) { serviceContext.put("subject", productStoreEmail.getString("subject")); serviceContext.put("sendFrom", productStoreEmail.get("fromAddress")); serviceContext.put("sendCc", productStoreEmail.get("ccAddress")); serviceContext.put("sendBcc", productStoreEmail.get("bccAddress")); serviceContext.put("contentType", productStoreEmail.get("contentType")); } else { GenericValue emailTemplateSetting = null; try { emailTemplateSetting = EntityQuery.use(delegator).from("EmailTemplateSetting").where("emailTemplateSettingId", "EMAIL_PASSWORD").cache().queryOne(); } catch (GenericEntityException e) { Debug.logError(e, module); } if (emailTemplateSetting != null) { String subject = emailTemplateSetting.getString("subject"); subject = FlexibleStringExpander.expandString(subject, UtilMisc.toMap("userLoginId", userLoginId)); serviceContext.put("subject", subject); serviceContext.put("sendFrom", emailTemplateSetting.get("fromAddress")); } else { serviceContext.put("subject", UtilProperties.getMessage(resource, "loginservices.password_reminder_subject", UtilMisc.toMap("userLoginId", userLoginId), UtilHttp.getLocale(request))); serviceContext.put("sendFrom", EntityUtilProperties.getPropertyValue("general", "defaultFromEmailAddress", delegator)); } } serviceContext.put("sendTo", emails.toString()); serviceContext.put("partyId", party.getString("partyId")); try { Map<String, Object> result = dispatcher.runSync("sendMailHiddenInLogFromScreen", serviceContext); if (ModelService.RESPOND_ERROR.equals(result.get(ModelService.RESPONSE_MESSAGE))) { Map<String, Object> messageMap = UtilMisc.toMap("errorMessage", result.get(ModelService.ERROR_MESSAGE)); errMsg = UtilProperties.getMessage(resource, "loginevents.error_unable_email_password_contact_customer_service_errorwas", messageMap, UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } } catch (GenericServiceException e) { Debug.logWarning(e, "", module); errMsg = UtilProperties.getMessage(resource, "loginevents.error_unable_email_password_contact_customer_service", UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } // don't save password until after it has been sent if (useEncryption) { try { supposedUserLogin.store(); } catch (GenericEntityException e) { Debug.logWarning(e, "", module); Map<String, String> messageMap = UtilMisc.toMap("errorMessage", e.toString()); errMsg = UtilProperties.getMessage(resource, "loginevents.error_saving_new_password_email_not_correct_password", messageMap, UtilHttp.getLocale(request)); request.setAttribute("_ERROR_MESSAGE_", errMsg); return "error"; } } if (useEncryption) { errMsg = UtilProperties.getMessage(resource, "loginevents.new_password_createdandsent_check_email", UtilHttp.getLocale(request)); request.setAttribute("_EVENT_MESSAGE_", errMsg); } else { errMsg = UtilProperties.getMessage(resource, "loginevents.new_password_sent_check_email", UtilHttp.getLocale(request)); request.setAttribute("_EVENT_MESSAGE_", errMsg); } return "success"; } public static String storeCheckLogin(HttpServletRequest request, HttpServletResponse response) { String responseString = LoginWorker.checkLogin(request, response); if ("error".equals(responseString)) { return responseString; } // if we are logged in okay, do the check store customer role return ProductEvents.checkStoreCustomerRole(request, response); } public static String storeLogin(HttpServletRequest request, HttpServletResponse response) { String responseString = LoginWorker.login(request, response); if (!"success".equals(responseString)) { return responseString; } if ("Y".equals(request.getParameter("rememberMe"))) { setUsername(request, response); } // if we logged in okay, do the check store customer role return ProductEvents.checkStoreCustomerRole(request, response); } public static String getUsername(HttpServletRequest request) { String cookieUsername = null; Cookie[] cookies = request.getCookies(); if (Debug.verboseOn()) Debug.logVerbose("Cookies:" + cookies, module); if (cookies != null) { for (Cookie cookie: cookies) { if (cookie.getName().equals(usernameCookieName)) { cookieUsername = cookie.getValue(); break; } } } return cookieUsername; } public static void setUsername(HttpServletRequest request, HttpServletResponse response) { HttpSession session = request.getSession(); Delegator delegator = (Delegator) request.getAttribute("delegator"); String domain = EntityUtilProperties.getPropertyValue("url", "cookie.domain", delegator); // first try to get the username from the cookie synchronized (session) { if (UtilValidate.isEmpty(getUsername(request))) { // create the cookie and send it back Cookie cookie = new Cookie(usernameCookieName, request.getParameter("USERNAME")); cookie.setMaxAge(60 * 60 * 24 * 365); cookie.setPath("/"); cookie.setDomain(domain); response.addCookie(cookie); } } } }