/** * The contents of this file are subject to the Mozilla Public License * Version 1.1 (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.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations under * the License. * * The Original Code is OpenELIS code. * * Copyright (C) The Minnesota Department of Health. All Rights Reserved. * * Contributor(s): CIRG, University of Washington, Seattle WA. */ package us.mn.state.health.lims.login.action; import java.util.HashSet; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.PropertyUtils; import org.apache.struts.action.ActionForm; import org.apache.struts.action.ActionForward; import org.apache.struts.action.ActionMapping; import org.apache.struts.action.ActionMessages; import us.mn.state.health.lims.common.action.BaseActionForm; import us.mn.state.health.lims.common.action.IActionConstants; import us.mn.state.health.lims.common.log.LogEvent; import us.mn.state.health.lims.common.util.SystemConfiguration; import us.mn.state.health.lims.common.util.validator.ActionError; import us.mn.state.health.lims.hibernate.HibernateUtil; import us.mn.state.health.lims.login.dao.LoginDAO; import us.mn.state.health.lims.login.dao.UserModuleDAO; import us.mn.state.health.lims.login.daoimpl.LoginDAOImpl; import us.mn.state.health.lims.login.daoimpl.UserModuleDAOImpl; import us.mn.state.health.lims.login.valueholder.Login; import us.mn.state.health.lims.login.valueholder.UserSessionData; import us.mn.state.health.lims.systemuser.dao.SystemUserDAO; import us.mn.state.health.lims.systemuser.daoimpl.SystemUserDAOImpl; import us.mn.state.health.lims.systemuser.valueholder.SystemUser; import us.mn.state.health.lims.systemusermodule.dao.PermissionAgentModuleDAO; import us.mn.state.health.lims.systemusermodule.daoimpl.RoleModuleDAOImpl; import us.mn.state.health.lims.systemusermodule.valueholder.RoleModule; import us.mn.state.health.lims.userrole.dao.UserRoleDAO; import us.mn.state.health.lims.userrole.daoimpl.UserRoleDAOImpl; /** * @author Hung Nguyen (Hung.Nguyen@health.state.mn.us) * bugzilla 2286, added password expired day reminder after user login * added force user to change password after number of days * added lock/lock user account after number of failed attempts */ public class LoginValidateAction extends LoginBaseAction { protected ActionForward performAction(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { String forward = FWD_SUCCESS; BaseActionForm dynaForm = (BaseActionForm) form; // server-side validation (validation.xml) ActionMessages errors = dynaForm.validate(mapping, request); if (errors != null && errors.size() > 0) { saveErrors(request, errors); return mapping.findForward(FWD_FAIL); } Login login = new Login(); PropertyUtils.copyProperties(login, dynaForm); login.setLoginName(login.getLoginName().trim()); org.hibernate.Transaction tx = HibernateUtil.getSession().beginTransaction(); LoginDAO loginDAO = new LoginDAOImpl(); Login userInfo = loginDAO.getUserProfile(login.getLoginName()); Login loginInfo = loginDAO.getValidateLogin(login); HibernateUtil.closeSession(); //if invalid loginName entered if ( userInfo == null ) { HibernateUtil.closeSession(); errors = new ActionMessages(); ActionError error = new ActionError("login.error.message", null, null); errors.add(ActionMessages.GLOBAL_MESSAGE, error); saveErrors(request, errors); return mapping.findForward(FWD_FAIL); } else { //if valid loginName entered then continue to check if ( userInfo.getAccountDisabled().equalsIgnoreCase(YES) ) { errors = new ActionMessages(); ActionError error = new ActionError("login.error.account.disable", null, null); errors.add(ActionMessages.GLOBAL_MESSAGE, error); saveErrors(request, errors); return mapping.findForward(FWD_FAIL); } if ( userInfo.getAccountLocked().equalsIgnoreCase(YES) ) { errors = new ActionMessages(); //ActionError error = new ActionError("login.error.account.lock", null, null); //errors.add(ActionMessages.GLOBAL_MESSAGE, error); //saveErrors(request, errors); //return mapping.findForward(FWD_FAIL); if ( request.getSession().getAttribute(ACCOUNT_LOCK_TIME) != null ) { lockUnlockUserAccount(errors,request,userInfo); } else { ActionError error = new ActionError("login.error.account.lock", null, null); errors.add(ActionMessages.GLOBAL_MESSAGE, error); saveErrors(request, errors); } return mapping.findForward(FWD_FAIL); } if ( userInfo.getPasswordExpiredDayNo() <= 0 ) { errors = new ActionMessages(); ActionError error = new ActionError("login.error.password.expired", null, null); errors.add(ActionMessages.GLOBAL_MESSAGE, error); saveErrors(request, errors); return mapping.findForward(FWD_FAIL); } //verify loginName and password loginInfo = loginDAO.getValidateLogin(login); if ( loginInfo == null ) { int loginUserFailAttemptCount = 0; int loginUserFailAttemptCountDefault = Integer.parseInt(SystemConfiguration.getInstance().getLoginUserFailAttemptCount()); if (request.getSession().getAttribute(LOGIN_FAILED_CNT) != null) { loginUserFailAttemptCount = Integer.parseInt((String)request.getSession().getAttribute(LOGIN_FAILED_CNT)); } loginUserFailAttemptCount++; request.getSession().setAttribute(LOGIN_FAILED_CNT, String.valueOf(loginUserFailAttemptCount)); //lock account after number of failed attempts if ( loginUserFailAttemptCount == loginUserFailAttemptCountDefault ) { tx = HibernateUtil.getSession().beginTransaction(); login = loginDAO.getUserProfile(login.getLoginName()); login.setAccountLocked(YES); loginDAO.lockAccount(login); tx.commit(); HibernateUtil.closeSession(); errors = new ActionMessages(); ActionError error = new ActionError("login.error.account.lock", null); errors.add(ActionMessages.GLOBAL_MESSAGE, error); saveErrors(request, errors); lockUnlockUserAccount(errors,request,userInfo); request.getSession().removeAttribute(LOGIN_FAILED_CNT); return mapping.findForward(FWD_FAIL); } errors = new ActionMessages(); ActionError error = new ActionError("login.error.attempt.message", String.valueOf(loginUserFailAttemptCount), String.valueOf(loginUserFailAttemptCountDefault), SystemConfiguration.getInstance().getLoginUserAccountUnlockMinute(), null); errors.add(ActionMessages.GLOBAL_MESSAGE, error); saveErrors(request, errors); return mapping.findForward(FWD_FAIL); } else { if ( (loginInfo.getPasswordExpiredDayNo() <= Integer.parseInt(SystemConfiguration.getInstance().getLoginUserPasswordExpiredReminderDay())) && (loginInfo.getPasswordExpiredDayNo() > Integer.parseInt(SystemConfiguration.getInstance().getLoginUserChangePasswordAllowDay())) ) { errors = new ActionMessages(); ActionError error = new ActionError("login.password.expired.reminder", loginInfo.getPasswordExpiredDayNo(), null); errors.add(ActionMessages.GLOBAL_MESSAGE, error); saveErrors(request, errors); } else if ( (loginInfo.getPasswordExpiredDayNo() <= Integer.parseInt(SystemConfiguration.getInstance().getLoginUserChangePasswordAllowDay())) && (loginInfo.getPasswordExpiredDayNo() > 0) ) { errors = new ActionMessages(); ActionError error = new ActionError("login.password.expired.force.notice", loginInfo.getPasswordExpiredDayNo(), loginInfo.getPasswordExpiredDayNo(), null); errors.add(ActionMessages.GLOBAL_MESSAGE, error); saveErrors(request, errors); return mapping.findForward(FWD_CHANGE_PASS); } if ( loginInfo.getSystemUserId() == 0 ) { errors = new ActionMessages(); ActionError error = new ActionError("login.error.system.user.id", loginInfo.getLoginName(), null); errors.add(ActionMessages.GLOBAL_MESSAGE, error); saveErrors(request, errors); return mapping.findForward(FWD_FAIL); } else { SystemUserDAO systemUserDAO = new SystemUserDAOImpl(); SystemUser su = new SystemUser(); su.setId(String.valueOf(loginInfo.getSystemUserId())); systemUserDAO.getData(su); //setup the user timeout in seconds int timeOut = Integer.parseInt((String)loginInfo.getUserTimeOut()); request.getSession().setMaxInactiveInterval(timeOut*60); UserSessionData usd = new UserSessionData(); usd.setSytemUserId(loginInfo.getSystemUserId()); usd.setLoginName(loginInfo.getLoginName()); usd.setElisUserName(su.getNameForDisplay()); usd.setUserTimeOut(timeOut*60); request.getSession().setAttribute(USER_SESSION_DATA,usd); boolean showAdminMenu = loginInfo.getIsAdmin().equalsIgnoreCase(YES); if( SystemConfiguration.getInstance().getPermissionAgent().equals("ROLE")){ HashSet<String> permittedPages = getPermittedForms(usd.getSystemUserId()); request.getSession().setAttribute(IActionConstants.PERMITTED_ACTIONS_MAP, permittedPages); showAdminMenu |= permittedPages.contains("MasterList"); } } //cleanup session if (request.getSession().getAttribute(LOGIN_FAILED_CNT) != null) request.getSession().removeAttribute(LOGIN_FAILED_CNT); if (request.getSession().getAttribute(ACCOUNT_LOCK_TIME) != null ) request.getSession().removeAttribute(ACCOUNT_LOCK_TIME); if ( loginInfo.getIsAdmin().equalsIgnoreCase(YES) ) //bugzilla 2154 LogEvent.logInfo("LoginValidateAction","performAction()","======> USER TYPE: ADMIN"); else { //bugzilla 2154 LogEvent.logInfo("LoginValidateAction","performAction()","======> USER TYPE: NON-ADMIN"); //bugzilla 2160 UserModuleDAO userModuleDAO = new UserModuleDAOImpl(); if ( !userModuleDAO.isUserModuleFound(request) ) { errors = new ActionMessages(); ActionError error = new ActionError("login.error.no.module", null, null); errors.add(ActionMessages.GLOBAL_MESSAGE, error); saveErrors(request, errors); return mapping.findForward(FWD_FAIL); } } } } return mapping.findForward(forward); } @SuppressWarnings("unchecked") private HashSet<String> getPermittedForms(int systemUserId) { HashSet<String> permittedPages = new HashSet<String>(); UserRoleDAO userRoleDAO = new UserRoleDAOImpl(); List<String> roleIds = userRoleDAO.getRoleIdsForUser( Integer.toString(systemUserId)); PermissionAgentModuleDAO roleModuleDAO = new RoleModuleDAOImpl(); for( String roleId : roleIds){ List<RoleModule> roleModules = roleModuleDAO.getAllPermissionModulesByAgentId(Integer.parseInt(roleId)); for( RoleModule roleModule : roleModules){ permittedPages.add( roleModule.getSystemModule().getSystemModuleName()); } } return permittedPages; } /** * Account is locked/unlock after the user entered wrong password (3 times) * @param errors the ActionMessages * @param request the HttpServletRequest * @param login the user login object */ private void lockUnlockUserAccount(ActionMessages errors, HttpServletRequest request, Login login) { java.util.Calendar loginTime = java.util.Calendar.getInstance(); if ( request.getSession().getAttribute(ACCOUNT_LOCK_TIME) != null ) { loginTime = (java.util.Calendar)request.getSession().getAttribute(ACCOUNT_LOCK_TIME); } else { int lockMinute = Integer.parseInt(SystemConfiguration.getInstance().getLoginUserAccountUnlockMinute()); loginTime.add(java.util.Calendar.MINUTE, +lockMinute); request.getSession().setAttribute(ACCOUNT_LOCK_TIME, loginTime); } java.util.Calendar now = java.util.Calendar.getInstance(); int diff = Integer.parseInt(String.valueOf((loginTime.getTimeInMillis()-now.getTimeInMillis())/1000)); if ( diff > 0 ) { int seconds = (int)(diff % 60); int minutes = (int)((diff/60) % 60); int hours = (int)((diff/3600) % 24); String secondsStr = (seconds<10 ? "0" : "")+ seconds; String minutesStr = (minutes<10 ? "0" : "")+ minutes; String hoursStr = (hours<10 ? "0" : "")+ hours; String unlockTime = hoursStr + ":" + minutesStr + ":" + secondsStr; ActionError error = new ActionError("login.user.account.lock.message", unlockTime, null); errors.add(ActionMessages.GLOBAL_MESSAGE, error); saveErrors(request, errors); } else { request.getSession().removeAttribute(ACCOUNT_LOCK_TIME); org.hibernate.Transaction tx = HibernateUtil.getSession().beginTransaction(); LoginDAO loginDAO = new LoginDAOImpl(); loginDAO.unlockAccount(login); login.setAccountLocked(NO); tx.commit(); HibernateUtil.closeSession(); ActionError error = new ActionError("login.user.account.unlock.message", null); errors.add(ActionMessages.GLOBAL_MESSAGE, error); saveErrors(request, errors); } } protected String getPageTitleKey() { return null; } protected String getPageSubtitleKey() { return null; } }