/****************************************************************************** * Copyright (C) 2012 Elaine Tan * * Copyright (C) 2012 Trek Global * This program is free software; you can redistribute it and/or modify it * * under the terms version 2 of the GNU General Public License as published * * by the Free Software Foundation. This program is distributed in the hope * * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * * with this program; if not, write to the Free Software Foundation, Inc., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * *****************************************************************************/ package org.adempiere.webui.panel; import java.util.ArrayList; import java.util.Properties; import org.adempiere.exceptions.AdempiereException; import org.adempiere.util.Callback; import org.adempiere.webui.LayoutUtils; import org.adempiere.webui.apps.AEnv; import org.adempiere.webui.component.Combobox; import org.adempiere.webui.component.ConfirmPanel; import org.adempiere.webui.component.Label; import org.adempiere.webui.component.Messagebox; import org.adempiere.webui.component.Textbox; import org.adempiere.webui.component.Window; import org.adempiere.webui.session.SessionManager; import org.adempiere.webui.theme.ITheme; import org.adempiere.webui.theme.ThemeManager; import org.adempiere.webui.util.ZKUpdateUtil; import org.adempiere.webui.window.LoginWindow; import org.compiere.model.MPasswordHistory; import org.compiere.model.MPasswordRule; import org.compiere.model.MSysConfig; import org.compiere.model.MUser; import org.compiere.util.CLogger; import org.compiere.util.Env; import org.compiere.util.KeyNamePair; import org.compiere.util.Login; import org.compiere.util.Msg; import org.compiere.util.Trx; import org.compiere.util.Util; import org.zkoss.zhtml.Div; import org.zkoss.zhtml.Table; import org.zkoss.zhtml.Td; import org.zkoss.zhtml.Tr; import org.zkoss.zk.ui.WrongValueException; import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.Events; import org.zkoss.zk.ui.util.Clients; import org.zkoss.zul.Image; /** * Change Password dialog * @author Elaine * @date August 30, 2012 */ public class ChangePasswordPanel extends Window implements EventListener { /** * generated serial id */ private static final long serialVersionUID = -4117126419866788951L; private static final CLogger logger = CLogger.getCLogger(ChangePasswordPanel.class); protected LoginWindow wndLogin; /** Context */ protected Properties m_ctx; /** Username */ protected String m_userName; /** Password */ protected String m_userPassword; protected KeyNamePair[] m_clientKNPairs; protected boolean m_show = true; protected Label lblOldPassword; protected Label lblNewPassword; protected Label lblRetypeNewPassword; protected Label lblSecurityQuestion; protected Label lblAnswer; protected Combobox lstSecurityQuestion; protected Textbox txtOldPassword; protected Textbox txtNewPassword; protected Textbox txtRetypeNewPassword; protected Textbox txtAnswer; /** * @param ctx * @param loginWindow * @param userName * @param userPassword * @param show * @param clientsKNPairs */ public ChangePasswordPanel(Properties ctx, LoginWindow loginWindow, String userName, String userPassword, boolean show, KeyNamePair[] clientsKNPairs) { this.wndLogin = loginWindow; m_ctx = ctx; m_userName = userName; m_userPassword = userPassword; m_show = show; m_clientKNPairs = clientsKNPairs; initComponents(); init(); this.setId("changePasswordPanel"); this.setSclass("login-box"); } private void init() { createUI(); } /** * Layout dialog */ protected void createUI() { Div div = new Div(); div.setSclass(ITheme.LOGIN_BOX_HEADER_CLASS); Label label = new Label(Msg.getMsg(m_ctx, "ChangePassword")); label.setSclass(ITheme.LOGIN_BOX_HEADER_TXT_CLASS); div.appendChild(label); this.appendChild(div); Table table = new Table(); table.setId("grdChangePassword"); table.setDynamicProperty("cellpadding", "0"); table.setDynamicProperty("cellspacing", "5"); table.setSclass(ITheme.LOGIN_BOX_BODY_CLASS); this.appendChild(table); Tr tr = new Tr(); table.appendChild(tr); Td td = new Td(); td.setSclass(ITheme.LOGIN_BOX_HEADER_LOGO_CLASS); tr.appendChild(td); td.setDynamicProperty("colspan", "2"); Image image = new Image(); image.setSrc(ThemeManager.getLargeLogo()); td.appendChild(image); tr = new Tr(); tr.setId("rowOldPassword"); table.appendChild(tr); td = new Td(); tr.appendChild(td); td.setSclass(ITheme.LOGIN_LABEL_CLASS); td.appendChild(lblOldPassword); td = new Td(); td.setSclass(ITheme.LOGIN_FIELD_CLASS); tr.appendChild(td); td.appendChild(txtOldPassword); tr = new Tr(); tr.setId("rowNewPassword"); table.appendChild(tr); td = new Td(); tr.appendChild(td); td.setSclass(ITheme.LOGIN_LABEL_CLASS); td.appendChild(lblNewPassword); td = new Td(); td.setSclass(ITheme.LOGIN_FIELD_CLASS); tr.appendChild(td); td.appendChild(txtNewPassword); tr = new Tr(); tr.setId("rowRetypeNewPassword"); table.appendChild(tr); td = new Td(); tr.appendChild(td); td.setSclass(ITheme.LOGIN_LABEL_CLASS); td.appendChild(lblRetypeNewPassword); td = new Td(); td.setSclass(ITheme.LOGIN_FIELD_CLASS); tr.appendChild(td); td.appendChild(txtRetypeNewPassword); tr = new Tr(); tr.setId("rowSecurityQuestion"); table.appendChild(tr); td = new Td(); tr.appendChild(td); td.setSclass(ITheme.LOGIN_LABEL_CLASS); td.appendChild(lblSecurityQuestion); td = new Td(); td.setSclass(ITheme.LOGIN_FIELD_CLASS); tr.appendChild(td); td.appendChild(lstSecurityQuestion); tr = new Tr(); tr.setId("rowAnswer"); table.appendChild(tr); td = new Td(); tr.appendChild(td); td.setSclass(ITheme.LOGIN_LABEL_CLASS); td.appendChild(lblAnswer); td = new Td(); td.setSclass(ITheme.LOGIN_FIELD_CLASS); tr.appendChild(td); td.appendChild(txtAnswer); div = new Div(); div.setSclass(ITheme.LOGIN_BOX_FOOTER_CLASS); ConfirmPanel pnlButtons = new ConfirmPanel(true); pnlButtons.addActionListener(this); LayoutUtils.addSclass(ITheme.LOGIN_BOX_FOOTER_PANEL_CLASS, pnlButtons); ZKUpdateUtil.setWidth(pnlButtons, null); pnlButtons.getButton(ConfirmPanel.A_OK).setSclass(ITheme.LOGIN_BUTTON_CLASS); pnlButtons.getButton(ConfirmPanel.A_CANCEL).setSclass(ITheme.LOGIN_BUTTON_CLASS); div.appendChild(pnlButtons); this.appendChild(div); } /** * Create components */ private void initComponents() { lblOldPassword = new Label(); lblOldPassword.setId("lblOldPassword"); lblOldPassword.setValue(Msg.getMsg(m_ctx, "Old Password")); lblNewPassword = new Label(); lblNewPassword.setId("lblNewPassword"); lblNewPassword.setValue(Msg.getMsg(m_ctx, "New Password")); lblRetypeNewPassword = new Label(); lblRetypeNewPassword.setId("lblRetypeNewPassword"); lblRetypeNewPassword.setValue(Msg.getMsg(m_ctx, "New Password Confirm")); lblSecurityQuestion = new Label(); lblSecurityQuestion.setId("lblSecurityQuestion"); lblSecurityQuestion.setValue(Msg.getMsg(m_ctx, "SecurityQuestion")); lblAnswer = new Label(); lblAnswer.setId("lblAnswer"); lblAnswer.setValue(Msg.getMsg(m_ctx, "Answer")); lstSecurityQuestion = new Combobox(); lstSecurityQuestion.setAutocomplete(true); lstSecurityQuestion.setAutodrop(true); lstSecurityQuestion.setId("lstSecurityQuestion"); ZKUpdateUtil.setWidth(lstSecurityQuestion, "220px"); lstSecurityQuestion.getItems().clear(); for (int i = 1; i <= ResetPasswordPanel.NO_OF_SECURITY_QUESTION; i++) lstSecurityQuestion.appendItem(Msg.getMsg(m_ctx, ResetPasswordPanel.SECURITY_QUESTION_PREFIX + i), ResetPasswordPanel.SECURITY_QUESTION_PREFIX + i); txtOldPassword = new Textbox(); txtOldPassword.setId("txtOldPassword"); txtOldPassword.setType("password"); txtOldPassword.setCols(25); ZKUpdateUtil.setWidth(txtOldPassword, "220px"); txtNewPassword = new Textbox(); txtNewPassword.setId("txtNewPassword"); txtNewPassword.setType("password"); txtNewPassword.setCols(25); txtNewPassword.addEventListener(Events.ON_BLUR, this); ZKUpdateUtil.setWidth(txtNewPassword, "220px"); txtRetypeNewPassword = new Textbox(); txtRetypeNewPassword.setId("txtRetypeNewPassword"); txtRetypeNewPassword.setType("password"); txtRetypeNewPassword.setCols(25); txtRetypeNewPassword.addEventListener(Events.ON_BLUR, this); ZKUpdateUtil.setWidth(txtRetypeNewPassword, "220px"); txtAnswer = new Textbox(); txtAnswer.setId("txtAnswer"); txtAnswer.setCols(25); ZKUpdateUtil.setWidth(txtAnswer, "220px"); } @Override public void onEvent(Event event) { if (event.getTarget().getId().equals(ConfirmPanel.A_OK)) { validateChangePassword(); } else if (event.getTarget().getId().equals(ConfirmPanel.A_CANCEL)) { SessionManager.logoutSession(); } else if (event.getTarget() == txtNewPassword) { MPasswordRule pwdrule = MPasswordRule.getRules(Env.getCtx(), null); if (pwdrule != null) { try { pwdrule.validate(Login.getAppUser(m_userName), txtNewPassword.getValue(), new ArrayList()); } catch (Exception e) { throw new WrongValueException(txtNewPassword, e.getMessage()); } } } else if (event.getTarget() == txtRetypeNewPassword) { if (!txtNewPassword.getValue().equals(txtRetypeNewPassword.getValue())) throw new WrongValueException(txtRetypeNewPassword, Msg.getMsg(m_ctx, "PasswordNotMatch")); } } /** * Validate new password */ public void validateChangePassword() { Clients.clearBusy(); String oldPassword = txtOldPassword.getValue(); String newPassword = txtNewPassword.getValue(); String retypeNewPassword = txtRetypeNewPassword.getValue(); String securityQuestion = null; if (lstSecurityQuestion.getSelectedItem() != null) securityQuestion = (String) lstSecurityQuestion.getSelectedItem().getLabel(); String answer = txtAnswer.getValue(); if (Util.isEmpty(oldPassword)) throw new IllegalArgumentException(Msg.getMsg(m_ctx, "OldPasswordMandatory")); if (Util.isEmpty(retypeNewPassword)) throw new IllegalArgumentException(Msg.getMsg(m_ctx, "NewPasswordConfirmMandatory")); if (!newPassword.equals(retypeNewPassword)) throw new IllegalArgumentException(Msg.getMsg(m_ctx, "PasswordNotMatch")); if (Util.isEmpty(securityQuestion)) throw new IllegalArgumentException(Msg.getMsg(m_ctx, "SecurityQuestionMandatory")); if (Util.isEmpty(answer)) throw new IllegalArgumentException(Msg.getMsg(m_ctx, "AnswerMandatory")); if (!oldPassword.equals(m_userPassword)) throw new IllegalArgumentException(Msg.getMsg(m_ctx, "OldPasswordNoMatch")); if (MSysConfig.getBooleanValue(MSysConfig.CHANGE_PASSWORD_MUST_DIFFER, true)) { if (oldPassword.equals(newPassword)) throw new IllegalArgumentException(Msg.getMsg(m_ctx, "NewPasswordMustDiffer")); } StringBuilder tenantsChanged = new StringBuilder(); Trx trx = null; try { String trxName = Trx.createTrxName("ChangePasswordTrx"); trx = Trx.get(trxName, true); trx.setDisplayName(getClass().getName()+"_validateChangePassword"); for (KeyNamePair clientKNPair : m_clientKNPairs) { int clientId = clientKNPair.getKey(); Env.setContext(m_ctx, Env.AD_CLIENT_ID, clientId); MUser user = MUser.get(m_ctx, Login.getAppUser(m_userName)); if (user == null) { trx.rollback(); logger.severe("Could not find user '" + m_userName + "'"); throw new AdempiereException("Could not find user"); } user.set_ValueOfColumn("Password", newPassword); // will be hashed and validate on saveEx user.setIsExpired(false); user.setSecurityQuestion(securityQuestion); user.setAnswer(answer); user.saveCrossTenantSafeEx(trx.getTrxName()); if (tenantsChanged.length() > 0) tenantsChanged.append(", "); tenantsChanged.append(clientKNPair.getName()); } trx.commit(); } catch (AdempiereException e) { if (trx != null) trx.rollback(); throw e; } finally { if (trx != null) trx.close(); } String msg = Msg.getMsg(m_ctx, "NewPasswordValidForAllTenants", new Object[] {tenantsChanged}); Messagebox.showDialog(msg, AEnv.getDialogHeader(Env.getCtx(), 0), Messagebox.OK, Messagebox.INFORMATION, new Callback() { @Override public void onCallback(Integer result) { wndLogin.loginOk(m_userName, m_show, m_clientKNPairs); } }); } }