/** * ESUP-Portail Helpdesk - Copyright (c) 2004-2009 ESUP-Portail consortium. */ package org.esupportail.helpdesk.web.controllers; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.sql.Timestamp; import java.util.HashMap; import java.util.Map; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.validator.EmailValidator; import org.esupportail.commons.aop.cache.RequestCache; import org.esupportail.commons.exceptions.UserNotFoundException; import org.esupportail.commons.exceptions.WebFlowException; import org.esupportail.commons.services.authentication.AuthUtils; import org.esupportail.commons.services.logging.Logger; import org.esupportail.commons.services.logging.LoggerImpl; import org.esupportail.commons.utils.Assert; import org.esupportail.commons.utils.ContextUtils; import org.esupportail.commons.utils.HttpUtils; import org.esupportail.commons.utils.SystemUtils; import org.esupportail.commons.utils.strings.StringUtils; import org.esupportail.commons.web.controllers.ExceptionController; import org.esupportail.helpdesk.domain.beans.User; import org.esupportail.helpdesk.domain.reporting.PasswordSender; import org.esupportail.helpdesk.services.authentication.Authenticator; /** * A bean to memorize the context of the application. */ public class SessionController extends AbstractDomainAwareBean { /** * The serialization id. */ private static final long serialVersionUID = 351880286499400587L; /** * Constant for state. */ private static final String NORMAL_STATE = "normal"; /** * Constant for state. */ private static final String CREATE_ACCOUNT_STATE = "createAccount"; /** * Constant for state. */ private static final String FORGOT_PASSWORD_STATE = "forgotPassword"; /** * A logger. */ private final Logger logger = new LoggerImpl(getClass()); /** * The exception controller (called when logging in/out). */ private ExceptionController exceptionController; /** * The authentication service. */ private Authenticator authenticator; /** * The password sender. */ private PasswordSender passwordSender; /** * The email. */ private String email; /** * The id. */ private String id; /** * The password. */ private String password; /** * The display name. */ private String displayName; /** * true to show the application login form. */ private boolean showApplicationLoginForm; /** * true to show the specific login form. */ private boolean showSpecificLoginForm; /** * The state. */ private String state; /** * The params to use to build the login URL. */ private Map<String, String> loginParams; /** * The CAS logout URL. */ private String casLogoutUrl; /** * True to show short menus. */ private boolean showShortMenu; /** * Constructor. */ public SessionController() { super(); email = null; password = null; showApplicationLoginForm = false; showSpecificLoginForm = false; state = NORMAL_STATE; displayName = null; loginParams = null; showShortMenu = true; } /** * @see org.esupportail.helpdesk.web.controllers.AbstractDomainAwareBean#afterPropertiesSetInternal() */ @Override public void afterPropertiesSetInternal() { super.afterPropertiesSetInternal(); Assert.notNull(this.exceptionController, "property exceptionController of class " + this.getClass().getName() + " can not be null"); Assert.notNull(this.authenticator, "property authenticator of class " + this.getClass().getName() + " can not be null"); Assert.notNull(this.passwordSender, "property passwordSender of class " + this.getClass().getName() + " can not be null"); } /** * @see java.lang.Object#toString() */ @Override public String toString() { return getClass().getName() + "#" + hashCode(); } /** * @return the current user, or null if guest. */ @Override public User getCurrentUser() { return authenticator.getUser(); } /** * @return the current client, or null if undefined. */ @Override @RequestCache public InetAddress getClient() { try { return HttpUtils.getClient(); } catch (UnknownHostException e) { logger.error(e); return null; } } /** * Unset the current user. */ public void unsetCurrentUser() { if (logger.isDebugEnabled()) { logger.debug("sessionController.unsetCurrentUser()"); } authenticator.unsetUser(); resetSessionLocale(); } /** * Set the current user. * @param user */ public void setCurrentUser(final User user) { authenticator.setApplicationUser(user); resetSessionLocale(); } /** * @return true if the current user is an application user. */ public boolean isApplicationUser() { User user = getCurrentUser(); return user != null && getUserStore().isApplicationUser(user); } /** * @return true if the CAS login form should be printed. */ public boolean isPrintCasLoginForm() { if (!getUserStore().isCasAuthAllowed()) { return false; } if (getCurrentUser() != null) { return false; } return true; } /** * @return true if the Shibboleth login form should be printed. */ public boolean isPrintShibbolethLoginForm() { if (!getUserStore().isShibbolethAuthAllowed()) { return false; } if (getCurrentUser() != null) { return false; } return true; } /** * @return true if the application login form should be printed. */ public boolean isPrintApplicationLoginForm() { if (!getUserStore().isApplicationAuthAllowed()) { return false; } if (getCurrentUser() != null) { return false; } return true; } /** * @return true if the specific login form should be printed. */ public boolean isPrintSpecificLoginForm() { if (!getUserStore().isSpecificAuthAllowed()) { return false; } if (getCurrentUser() != null) { return false; } return true; } /** * @return true if the logout button should be printed. */ @RequestCache public boolean isPrintLogout() { if (getCurrentUser() == null) { return false; } if (ContextUtils.isServlet()) { return true; } // ContextUtils.isPortlet() == true return getUserStore().isApplicationUser(getCurrentUser()) || getUserStore().isSpecificUser(getCurrentUser()); } /** * Redirect after login. * @param url */ protected void redirectAfterLogin(final String url) { FacesContext facesContext = FacesContext.getCurrentInstance(); ExternalContext externalContext = facesContext.getExternalContext(); try { externalContext.redirect(url); } catch (IOException e) { throw new WebFlowException("could not redirect to URL [" + url + "]", e); } facesContext.responseComplete(); } /** * Add the enter param to the login params so the redirector will be called. */ protected void addEnterParam() { if (loginParams == null) { loginParams = new HashMap<String, String>(); } loginParams.put("enter", ""); } /** * JSF callback. */ public void casLogin() { unsetCurrentUser(); addEnterParam(); redirectAfterLogin(getUrlBuilder().getUrl(AuthUtils.CAS, loginParams)); } /** * JSF callback. */ public void shibbolethLogin() { unsetCurrentUser(); addEnterParam(); redirectAfterLogin(getUrlBuilder().getUrl(AuthUtils.SHIBBOLETH, loginParams)); } /** * Authenticate thanks to the auth cookie. * @return true if correctly authenticated. */ public boolean cookieLogin() { HttpServletRequest request = HttpUtils.getHttpServletRequest(); if (request == null) { return false; } if (request.getCookies() == null) { return false; } for (Cookie cookie : request.getCookies()) { if (cookie != null && getUserStore().getAuthCookieName().equals(cookie.getName())) { User user = getUserStore().getUserWithAuthSecret(cookie.getValue()); if (user == null) { return false; } setCurrentUser(user); state = NORMAL_STATE; return true; } } return false; } /** * Install a auth cookie on the client. */ protected void installAuthCookie() { if (logger.isDebugEnabled()) { logger.debug("installAuthCookie()"); } HttpServletResponse response = HttpUtils.getHttpServletResponse(); if (response == null) { if (logger.isDebugEnabled()) { logger.debug("response is null"); } return; } User user = getCurrentUser(); Cookie cookie = getUserStore().renewAuthSecret(user); response.addCookie(cookie); if (logger.isDebugEnabled()) { logger.debug("added cookie " + cookie); } } /** * Remove the auth cookie on the client. */ protected void removeAuthCookie() { HttpServletResponse response = HttpUtils.getHttpServletResponse(); if (response != null) { User user = getCurrentUser(); Cookie cookie = getUserStore().removeAuthSecret(user); response.addCookie(cookie); } } /** * JSF callback. * @param redirect true to redirect after login * @return true if correctly authenticated. */ protected boolean applicationLogin(final boolean redirect) { if (logger.isDebugEnabled()) { logger.debug("applicationLogin(" + redirect + ")"); } String thePassword = password; password = null; if (email == null) { if (logger.isDebugEnabled()) { logger.debug("email is null"); } addErrorMessage("applicationLoginForm:email", "SESSION.MESSAGE.NULL_EMAIL"); return false; } if (!EmailValidator.getInstance().isValid(email)) { if (logger.isDebugEnabled()) { logger.debug("email is not valid"); } addErrorMessage(null, "SESSION.MESSAGE.INVALID_EMAIL", email); return false; } if (thePassword == null) { if (logger.isDebugEnabled()) { logger.debug("password is null"); } addErrorMessage("applicationLoginForm:password", "SESSION.MESSAGE.NULL_PASSWORD"); return false; } try { User user = getUserStore().authenticateApplicationUser(email, thePassword); if (user != null) { if (logger.isDebugEnabled()) { logger.debug("user successfully authenticated"); } setCurrentUser(user); addInfoMessage(null, "SESSION.MESSAGE.LOGIN_SUCCESS"); state = NORMAL_STATE; installAuthCookie(); if (redirect) { redirectAfterLogin( getUrlBuilder().getUrl(AuthUtils.APPLICATION, loginParams)); } return true; } if (logger.isDebugEnabled()) { logger.debug("password [" + thePassword + "] does not match"); } } catch (UserNotFoundException e) { if (logger.isDebugEnabled()) { logger.debug("user not found"); } // see below } addErrorMessage(null, "SESSION.MESSAGE.LOGIN_FAILURE"); return false; } /** * JSF callback. */ public void applicationLoginFromForm() { applicationLogin(true); } /** * Try to login from the redirector. */ public void applicationLoginFromRedirector() { applicationLogin(false); } /** * JSF callback. */ public void specificLogin() { if (logger.isDebugEnabled()) { logger.debug("specificLogin()"); } String thePassword = password; password = null; if (id == null) { if (logger.isDebugEnabled()) { logger.debug("id is null"); } addErrorMessage("specificLoginForm:id", "SESSION.MESSAGE.NULL_ID"); return; } if (thePassword == null) { if (logger.isDebugEnabled()) { logger.debug("password is null"); } addErrorMessage("specificLoginForm:password", "SESSION.MESSAGE.NULL_PASSWORD"); return; } try { User user = getUserStore().authenticateSpecificUser(id, thePassword); if (user != null) { if (logger.isDebugEnabled()) { logger.debug("user successfully authenticated"); } setCurrentUser(user); addInfoMessage(null, "SESSION.MESSAGE.LOGIN_SUCCESS"); state = NORMAL_STATE; installAuthCookie(); redirectAfterLogin( getUrlBuilder().getUrl(AuthUtils.SPECIFIC, loginParams)); return; } if (logger.isDebugEnabled()) { logger.debug("password [" + thePassword + "] does not match"); } } catch (UserNotFoundException e) { if (logger.isDebugEnabled()) { logger.debug("user not found"); } // see below } addErrorMessage(null, "SESSION.MESSAGE.LOGIN_FAILURE"); return; } /** * JSF callback. * @return a String. * @throws IOException */ public String logout() throws IOException { if (ContextUtils.isPortlet()) { User user = getCurrentUser(); Assert.notNull(user, "can not logout (not logged in)"); Assert.isTrue( getDomainService().getUserStore().isApplicationUser(getCurrentUser()), "can not logout (CAS or Shibboleth user in portlet mode)"); removeAuthCookie(); unsetCurrentUser(); // calling this method will reset all the beans of the application exceptionController.restart(); return "navigationWelcome"; } // servlet if (getDomainService().getUserStore().isApplicationUser(getCurrentUser())) { removeAuthCookie(); unsetCurrentUser(); exceptionController.restart(); return "navigationWelcome"; } if (getDomainService().getUserStore().isShibbolethUser(getCurrentUser())) { unsetCurrentUser(); exceptionController.restart(); return "navigationWelcome"; } FacesContext facesContext = FacesContext.getCurrentInstance(); ExternalContext externalContext = facesContext.getExternalContext(); HttpServletRequest request = (HttpServletRequest) externalContext.getRequest(); String returnUrl = request.getRequestURL().toString().replaceFirst("/stylesheets/[^/]*$", ""); String forwardUrl; Assert.hasText( casLogoutUrl, "property casLogoutUrl of class " + getClass().getName() + " is null"); forwardUrl = String.format(casLogoutUrl, StringUtils.utf8UrlEncode(returnUrl)); // note: the session beans will be kept even when invalidating // the session so they have to be reset (by the exception controller). // We invalidate the session however for the other attributes. request.getSession().invalidate(); request.getSession(true); // calling this method will reset all the beans of the application exceptionController.restart(); externalContext.redirect(forwardUrl); facesContext.responseComplete(); return null; } /** * JSF callback. */ public void forgotPassword() { if (email == null) { addErrorMessage("forgotPasswordForm:email", "SESSION.MESSAGE.NULL_EMAIL"); return; } if (!EmailValidator.getInstance().isValid(email)) { addErrorMessage(null, "SESSION.MESSAGE.INVALID_EMAIL", email); return; } try { passwordSender.sendPasswordEmail( getUserStore().getExistingApplicationUser(email), getCurrentUserLocale()); addInfoMessage(null, "SESSION.MESSAGE.PASSWORD_SENT", email); state = NORMAL_STATE; return; } catch (UserNotFoundException e) { addErrorMessage(null, "SESSION.MESSAGE.UNKNOWN_LOGIN", email); state = CREATE_ACCOUNT_STATE; } } /** * JSF callback. */ public void createAccount() { if (email == null) { addErrorMessage("createAccountForm:email", "SESSION.MESSAGE.NULL_EMAIL"); return; } if (displayName == null) { addErrorMessage("createAccountForm:displayName", "SESSION.MESSAGE.NULL_DISPLAY_NAME"); return; } if (!EmailValidator.getInstance().isValid(email)) { addErrorMessage(null, "SESSION.MESSAGE.INVALID_EMAIL", email); return; } try { getUserStore().getExistingApplicationUser(email); addErrorMessage(null, "SESSION.MESSAGE.ACCOUNT_EXISTS", email); gotoForgotPassword(); return; } catch (UserNotFoundException e) { getUserStore().createApplicationUser(email, displayName, getLocale()); addInfoMessage(null, "SESSION.MESSAGE.ACCOUNT_CREATED", email); state = NORMAL_STATE; return; } } /** * JSF callback. */ public void gotoLogin() { state = NORMAL_STATE; } /** * JSF callback. */ public void gotoForgotPassword() { password = null; state = FORGOT_PASSWORD_STATE; } /** * JSF callback. */ public void gotoCreateAccount() { password = null; state = CREATE_ACCOUNT_STATE; } /** * @return true to show the submit popup text. */ public boolean isShowSubmitPopupText() { if (getCurrentUser() == null) { return true; } return getCurrentUser().isShowSubmitPopupText(); } /** * @return true to show the submit popup image. */ public boolean isShowSubmitPopupImage() { if (getCurrentUser() == null) { return true; } return getCurrentUser().isShowSubmitPopupImage(); } /** * @return true to freeze the screen on submit. */ public boolean isFreezeScreenOnSubmit() { if (getCurrentUser() == null) { return true; } return getCurrentUser().isFreezeScreenOnSubmit(); } /** * @param exceptionController the exceptionController to set */ public void setExceptionController(final ExceptionController exceptionController) { this.exceptionController = exceptionController; } /** * @param authenticator the authenticator */ public void setAuthenticator(final Authenticator authenticator) { this.authenticator = authenticator; } /** * @return the email */ public String getEmail() { return email; } /** * @param email the email to set */ public void setEmail(final String email) { this.email = StringUtils.nullIfEmpty(email); } /** * @return the password */ public String getPassword() { return password; } /** * @param password the password to set */ public void setPassword(final String password) { this.password = StringUtils.nullIfEmpty(password); } /** * @return the showApplicationLoginForm */ public boolean isShowApplicationLoginForm() { return showApplicationLoginForm; } /** * @param showApplicationLoginForm the showApplicationLoginForm to set */ public void setShowApplicationLoginForm(final boolean showApplicationLoginForm) { this.showApplicationLoginForm = showApplicationLoginForm; } /** * @return the showSpecificLoginForm */ public boolean isShowSpecificLoginForm() { return showSpecificLoginForm; } /** * @param showSpecificLoginForm the showSpecificLoginForm to set */ public void setShowSpecificLoginForm(final boolean showSpecificLoginForm) { this.showSpecificLoginForm = showSpecificLoginForm; } /** * @return the displayName */ public String getDisplayName() { return displayName; } /** * @param displayName the displayName to set */ public void setDisplayName(final String displayName) { this.displayName = StringUtils.nullIfEmpty(displayName); } /** * @return the state */ public String getState() { return state; } /** * @return the loginParams */ protected Map<String, String> getLoginParams() { return loginParams; } /** * @param loginParams the loginParams to set */ public void setLoginParams(final Map<String, String> loginParams) { this.loginParams = loginParams; } /** * @return the exceptionController */ protected ExceptionController getExceptionController() { return exceptionController; } /** * @return the authenticator */ protected Authenticator getAuthenticator() { return authenticator; } /** * @param state the state to set */ protected void setState(final String state) { this.state = state; } /** * Set the normal state. */ public void setNormalState() { setState(NORMAL_STATE); } /** * @return the casLogoutUrl */ protected String getCasLogoutUrl() { return casLogoutUrl; } /** * @param casLogoutUrl the casLogoutUrl to set */ public void setCasLogoutUrl(final String casLogoutUrl) { this.casLogoutUrl = StringUtils.nullIfEmpty(casLogoutUrl); } /** * @return the current date. */ public Timestamp getNow() { return new Timestamp(System.currentTimeMillis()); } /** * Toggle the showShortMenu flag. */ public void toggleShowShortMenu() { showShortMenu = !showShortMenu; } /** * @return the showShortMenu */ public boolean isShowShortMenu() { return showShortMenu; } /** * @param showShortMenu the showShortMenu to set */ protected void setShowShortMenu(final boolean showShortMenu) { this.showShortMenu = showShortMenu; } /** * @return the free memory (Mb). */ public long getFreeMemory() { return SystemUtils.getFreeMemory(); } /** * @return the total memory (Mb). */ public long getTotalMemory() { return SystemUtils.getTotalMemory(); } /** * @return the max memory (Mb). */ public long getMaxMemory() { return SystemUtils.getMaxMemory(); } /** * @return the passwordSender */ protected PasswordSender getPasswordSender() { return passwordSender; } /** * @param passwordSender the passwordSender to set */ public void setPasswordSender(final PasswordSender passwordSender) { this.passwordSender = passwordSender; } /** * @return the id */ public String getId() { return id; } /** * @param id the id to set */ public void setId(final String id) { this.id = StringUtils.nullIfEmpty(id); } }