/******************************************************************************
* Product: Posterita Ajax UI *
* Copyright (C) 2007 Posterita Ltd. All Rights Reserved. *
* 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. *
* For the text or an alternative of this public license, you may reach us *
* Posterita Ltd., 3, Draper Avenue, Quatre Bornes, Mauritius *
* or via info@posterita.org or http://www.posterita.org/ *
* *
* Contributors: *
* - Heng Sin Low *
* *
* Sponsors: *
* - Idalica Corporation *
*****************************************************************************/
package org.adempiere.webui.window;
import java.sql.Timestamp;
import java.util.Locale;
import java.util.Properties;
import java.util.logging.Level;
import javax.servlet.http.HttpSession;
import org.adempiere.base.sso.ISSOPrincipalService;
import org.adempiere.base.sso.SSOUtils;
import org.adempiere.exceptions.AdempiereException;
import org.adempiere.util.Callback;
import org.adempiere.webui.AdempiereWebUI;
import org.adempiere.webui.IWebClient;
import org.adempiere.webui.component.Window;
import org.adempiere.webui.panel.ChangePasswordPanel;
import org.adempiere.webui.panel.LoginPanel;
import org.adempiere.webui.panel.ResetPasswordPanel;
import org.adempiere.webui.panel.RolePanel;
import org.adempiere.webui.panel.ValidateMFAPanel;
import org.adempiere.webui.session.SessionContextListener;
import org.adempiere.webui.session.SessionManager;
import org.adempiere.webui.theme.ThemeManager;
import org.adempiere.webui.util.UserPreference;
import org.adempiere.webui.util.ZkSSOUtils;
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.Language;
import org.compiere.util.Login;
import org.compiere.util.Msg;
import org.compiere.util.TimeUtil;
import org.compiere.util.Util;
import org.compiere.util.ValueNamePair;
import org.zkoss.util.Locales;
import org.zkoss.web.Attributes;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.Session;
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.metainfo.PageDefinition;
import org.zkoss.zk.ui.util.Clients;
/**
*
* @author Ashley G Ramdass
* @date Feb 25, 2007
* @version $Revision: 0.10 $
* @author Sendy Yagambrum
* @date July 18, 2007
*/
public class LoginWindow extends Window implements EventListener
{
/**
* generated serial id
*/
private static final long serialVersionUID = 8570332386555237381L;
protected static final CLogger log = CLogger.getCLogger(LoginWindow.class);
protected IWebClient app;
protected Properties ctx;
protected LoginPanel pnlLogin;
protected ResetPasswordPanel pnlResetPassword;
protected ChangePasswordPanel pnlChangePassword;
protected ValidateMFAPanel pnlValidateMFA = null;
protected RolePanel pnlRole;
private static final String ON_DEFER_LOGOUT = "onDeferLogout";
public LoginWindow() {}
/**
* Layout window
* @param app
*/
public void init(IWebClient app)
{
this.ctx = Env.getCtx();
this.app = app;
initComponents();
if (pnlLogin != null)
this.appendChild(pnlLogin);
this.setStyle("background-color: transparent");
// add listener on 'ENTER' key for the login window
addEventListener(Events.ON_OK,this);
this.addEventListener(ON_DEFER_LOGOUT, this);
setWidgetListener("onOK", "zAu.cmd0.showBusy(null)");
}
/**
* Create login panel
*/
private void initComponents()
{
Object token = getDesktop().getSession().getAttribute(ISSOPrincipalService.SSO_PRINCIPAL_SESSION_TOKEN);
if (token == null)
{
createLoginPanel();
}
else
{
ssoLogin(token);
}
}
/**
* Show role panel after SSO authentication.
*
* @param Session token for retrieving user and language.
*/
private void ssoLogin(Object token)
{
String errorMessage = null;
try
{
ISSOPrincipalService ssoPrincipal = SSOUtils.getSSOPrincipalService();
String username = ssoPrincipal.getUserName(token);
Language language = ssoPrincipal.getLanguage(token);
boolean isEmailLogin = MSysConfig.getBooleanValue(MSysConfig.USE_EMAIL_FOR_LOGIN, false);
if (Util.isEmpty(username))
throw new AdempiereException("No Apps " + (isEmailLogin ? "Email" : "User"));
if (language == null)
language = Language.getBaseLanguage();
Env.setContext(ctx, UserPreference.LANGUAGE_NAME, language.getName());
Locale locale = language.getLocale();
getDesktop().getSession().setAttribute(Attributes.PREFERRED_LOCALE, locale);
Login login = new Login(ctx);
boolean isShowRolePanel = MSysConfig.getBooleanValue(MSysConfig.SSO_SELECT_ROLE, true);
// show role panel when change role
if(getDesktop().getSession().hasAttribute(SSOUtils.ISCHANGEROLE_REQUEST))
isShowRolePanel = isShowRolePanel || (boolean) getDesktop().getSession().getAttribute(SSOUtils.ISCHANGEROLE_REQUEST);
KeyNamePair[] clients = login.getClients(username, null, null, token);
if (clients != null)
loginOk(username, isShowRolePanel, clients, true);
else
{
log.log(Level.WARNING,"No Client found for user:" + username);
ValueNamePair error = CLogger.retrieveError();
if (error == null)
error = CLogger.retrieveWarning();
errorMessage = Msg.getMsg(language, error.getValue(), new Object[] { error.getName() });
}
}
catch (Exception e)
{
log.log(Level.SEVERE, e.getMessage(), e);
errorMessage = e.getLocalizedMessage();
}
if (!Util.isEmpty(errorMessage))
{
ZkSSOUtils.setErrorMessageText(errorMessage);
Executions.sendRedirect(SSOUtils.ERROR_VALIDATION_URL);
}
}
/**
* Create login panel
*/
protected void createLoginPanel() {
pnlLogin = new LoginPanel(ctx, this);
}
/**
* After verification of user name and password.
* @param userName
* @param show
* @param clientsKNPairs
*/
public void loginOk(String userName, boolean show, KeyNamePair[] clientsKNPairs)
{
loginOk(userName, show, clientsKNPairs, false);
}
public void loginOk(String userName, boolean show, KeyNamePair[] clientsKNPairs, boolean isSSOLogin)
{
boolean isClientDefined = (clientsKNPairs.length == 1 || !Util.isEmpty(Env.getContext(ctx, Env.AD_USER_ID)));
if (pnlRole == null)
pnlRole = new RolePanel(ctx, this, userName, show, clientsKNPairs, isClientDefined);
if (isSSOLogin)
{
Executions.schedule(getDesktop(), e -> validateMFPanel(userName, show, clientsKNPairs, isClientDefined), new Event(SSOUtils.EVENT_ON_AFTER_SSOLOGIN));
}
else
{
validateMFPanel(userName, show, clientsKNPairs, isClientDefined);
}
}
private void validateMFPanel(String userName, boolean show, KeyNamePair[] clientsKNPairs, boolean isClientDefined)
{
if (isClientDefined) {
createValidateMFAPanel(null, isClientDefined, userName, show, clientsKNPairs);
} else {
showRolePanel(userName, show, clientsKNPairs, isClientDefined, false);
if (!pnlRole.show())
createValidateMFAPanel(null, isClientDefined, userName, show, clientsKNPairs);
}
}
/**
* Show role selection panel
* @param userName
* @param show
* @param clientsKNPairs
* @param isClientDefined
* @param isMFAValidated
*/
public void showRolePanel(String userName, boolean show, KeyNamePair[] clientsKNPairs, boolean isClientDefined, boolean isMFAValidated) {
this.getChildren().clear();
if (pnlRole.show()) {
this.appendChild(pnlRole);
} else if (isMFAValidated) {
pnlRole.validateRoles(isMFAValidated);
} else {
if (!isClientDefined)
if (pnlValidateMFA == null)
createValidateMFAPanel(null, isClientDefined, userName, show, clientsKNPairs);
else
this.appendChild(pnlValidateMFA);
}
}
/**
* Show change password panel
* @param userName
* @param userPassword
* @param show
* @param clientsKNPairs
*/
public void changePassword(String userName, String userPassword, boolean show, KeyNamePair[] clientsKNPairs)
{
Clients.clearBusy();
createChangePasswordPanel(userName, userPassword, show, clientsKNPairs);
this.getChildren().clear();
this.appendChild(pnlChangePassword);
}
/**
* Create change password panel
* @param userName
* @param userPassword
* @param show
* @param clientsKNPairs
*/
protected void createChangePasswordPanel(String userName,
String userPassword, boolean show, KeyNamePair[] clientsKNPairs) {
pnlChangePassword = new ChangePasswordPanel(ctx, this, userName, userPassword, show, clientsKNPairs);
}
/**
* Show reset password panel
* @param userName
* @param noSecurityQuestion
*/
public void resetPassword(String userName, boolean noSecurityQuestion)
{
createResetPasswordPanel(userName, noSecurityQuestion);
this.getChildren().clear();
this.appendChild(pnlResetPassword);
}
/**
* Create reset password panel
* @param userName
* @param noSecurityQuestion
*/
protected void createResetPasswordPanel(String userName,
boolean noSecurityQuestion) {
pnlResetPassword = new ResetPasswordPanel(ctx, this, userName, noSecurityQuestion);
}
/**
* Show MFA panel
* @param orgKNPair
* @param isClientDefined
* @param userName
* @param show
* @param clientsKNPairs
*/
public void validateMFA(KeyNamePair orgKNPair, boolean isClientDefined, String userName, boolean show, KeyNamePair[] clientsKNPairs) {
Clients.clearBusy();
createValidateMFAPanel(orgKNPair, isClientDefined, userName, show, clientsKNPairs);
}
/**
* Create and show MFA panel
* @param orgKNPair
* @param isClientDefined
* @param userName
* @param show
* @param clientsKNPairs
*/
private void createValidateMFAPanel(KeyNamePair orgKNPair, boolean isClientDefined, String userName, boolean show, KeyNamePair[] clientsKNPairs) {
if (pnlValidateMFA == null)
pnlValidateMFA = new ValidateMFAPanel(ctx, this, orgKNPair, isClientDefined, userName, show, clientsKNPairs);
if (pnlValidateMFA.show()) {
this.getChildren().clear();
this.appendChild(pnlValidateMFA);
}
}
/**
* Complete login process
* @param login
* @param m_orgKNPair
* @param component
*/
public void loginCompleted(Login login, KeyNamePair m_orgKNPair, Window component)
{
Session currSess = Executions.getCurrent().getDesktop().getSession();
HttpSession httpSess = (HttpSession) currSess.getNativeSession();
int timeout = MSysConfig.getIntValue(MSysConfig.ZK_SESSION_TIMEOUT_IN_SECONDS, -2,
Env.getAD_Client_ID(Env.getCtx()), Env.getAD_Org_ID(Env.getCtx()));
if (timeout != -2) // default to -2 meaning not set
httpSess.setMaxInactiveInterval(timeout);
String msg = login.validateLogin(m_orgKNPair);
if (!Util.isEmpty(msg)) {
Env.getCtx().clear();
Dialog.error(0, "Error", msg, new Callback() {
@Override
public void onCallback(Integer result) {
Events.echoEvent(new Event(ON_DEFER_LOGOUT, component));
}
});
return;
}
// See if a popup should encourage user to change its password
if (!MUser.get(Env.getCtx()).isNoPasswordReset()) {
int notifyDay = MSysConfig.getIntValue(MSysConfig.USER_LOCKING_PASSWORD_NOTIFY_DAY, 0);
int pwdAgeDay = MSysConfig.getIntValue(MSysConfig.USER_LOCKING_MAX_PASSWORD_AGE_DAY, 0);
if (notifyDay > 0 && pwdAgeDay > 0) {
Timestamp limit = TimeUtil.addDays(MUser.get(Env.getCtx()).getDatePasswordChanged(), pwdAgeDay);
Timestamp notifyAfter = TimeUtil.addDays(limit, -notifyDay);
Timestamp now = TimeUtil.getDay(null);
if (now.after(notifyAfter))
Dialog.warn(0, "", Msg.getMsg(Env.getCtx(), "YourPasswordWillExpireInDays",
new Object[] { TimeUtil.getDaysBetween(now, limit) }));
}
}
app.loginCompleted();
}
/**
* Login cancel by user. Show login panel again.
*/
public void loginCancelled()
{
createLoginPanel();
this.getChildren().clear();
this.appendChild(pnlLogin);
}
@Override
public void onEvent(Event event)
{
// check that 'ENTER' key is pressed
if (Events.ON_OK.equals(event.getName()))
{
/**
* LoginWindow can have as a child, either LoginPanel or RolePanel
* If LoginPanel is currently a child, validate login when
* 'ENTER' key is pressed or validate Roles if RolePanel is
* currently a child
*/
RolePanel rolePanel = (RolePanel)this.getFellowIfAny("rolePanel");
if (rolePanel != null)
{
rolePanel.validateRoles(false);
return;
}
LoginPanel loginPanel = (LoginPanel)this.getFellowIfAny("loginPanel");
if (loginPanel != null)
{
loginPanel.validateLogin();
return;
}
ChangePasswordPanel changePasswordPanel = (ChangePasswordPanel)this.getFellowIfAny("changePasswordPanel");
if (changePasswordPanel != null){
changePasswordPanel.validateChangePassword();
return;
}
ResetPasswordPanel resetPasswordPanel = (ResetPasswordPanel)this.getFellowIfAny("resetPasswordPanel");
if (resetPasswordPanel != null){
resetPasswordPanel.validate();
return;
}
ValidateMFAPanel validateMFAPanel = (ValidateMFAPanel)this.getFellowIfAny("validateMFAPanel");
if (validateMFAPanel != null){
validateMFAPanel.validateMFAComplete(true);
return;
}
} else if (ON_DEFER_LOGOUT.equals(event.getName())) {
SessionManager.logoutSession();
}
}
/**
* Show change role window
* @param locale
* @param ctx
*/
public void changeRole(Locale locale, Properties ctx)
{
Env.setCtx(ctx);
// clear the org ID - to force a logout if the user pushes Refresh on RolePanel
Env.setContext(ctx, "#AD_Org_ID_ChangeRole", Env.getAD_Org_ID(ctx));
Env.setContext(ctx, Env.AD_ORG_ID, "");
getDesktop().getSession().setAttribute(SessionContextListener.SESSION_CTX, ctx);
//reload theme preference
PageDefinition pageDefintion = Executions.getCurrent().getPageDefinition(ThemeManager.getThemeResource("preference.zul"));
Executions.createComponents(pageDefintion, this, null);
getDesktop().getSession().setAttribute(Attributes.PREFERRED_LOCALE, locale);
Locales.setThreadLocal(locale);
Login login = new Login(Env.getCtx());
MUser user = MUser.get(ctx, Env.getAD_User_ID(ctx));
String loginName;
boolean email_login = MSysConfig.getBooleanValue(MSysConfig.USE_EMAIL_FOR_LOGIN, false);
if (email_login)
loginName = user.getEMail();
else
loginName = user.getLDAPUser() != null ? user.getLDAPUser() : user.getName();
loginOk(loginName, true, login.getClients());
getDesktop().getSession().setAttribute(AdempiereWebUI.CHECK_AD_USER_ID_ATTR, Env.getAD_User_ID(ctx));
pnlRole.setChangeRole(true);
pnlRole.changeRole(ctx);
}
@Override
public void onPageDetached(Page page) {
setWidgetListener("onOK", null);
super.onPageDetached(page);
}
}