From 74c7660321afb87320b4e88a44aa68caa046d615 Mon Sep 17 00:00:00 2001 From: jeb228 Date: Wed, 7 Jul 2010 19:35:46 +0000 Subject: [PATCH] NIHVIVO-638 Check in first phase of changes to the Login form and backend. --- .../webapp/controller/edit/Authenticate.java | 730 ++++++++++++------ .../controller/edit/UserEditController.java | 2 +- .../controller/login/LoginProcessBean.java | 139 ++++ .../controller/login/LoginTemplateHelper.java | 225 ++++++ .../login/LoginTemplateHelperBase.java | 27 + webapp/web/images/iconAlert.png | Bin 0 -> 1478 bytes webapp/web/siteAdmin/loginForm.jsp | 116 +-- webapp/web/siteAdmin/siteAdminMain.jsp | 6 + webapp/web/siteAdmin/siteAdminScripts.jsp | 38 +- .../templates/edit/specific/user_retry.jsp | 2 +- .../body/login/forcedPasswordChange.ftl | 27 + .../templates/freemarker/body/login/login.ftl | 29 + 12 files changed, 999 insertions(+), 342 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/controller/login/LoginProcessBean.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/controller/login/LoginTemplateHelper.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/controller/login/LoginTemplateHelperBase.java create mode 100644 webapp/web/images/iconAlert.png create mode 100644 webapp/web/templates/freemarker/body/login/forcedPasswordChange.ftl create mode 100644 webapp/web/templates/freemarker/body/login/login.ftl diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/Authenticate.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/Authenticate.java index e54bd9e8e..36bcae212 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/Authenticate.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/Authenticate.java @@ -2,8 +2,12 @@ package edu.cornell.mannlib.vitro.webapp.controller.edit; +import java.io.IOException; +import java.io.UnsupportedEncodingException; import java.net.URLEncoder; -import java.util.Calendar; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -13,6 +17,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.apache.commons.codec.binary.Hex; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -22,244 +27,529 @@ import edu.cornell.mannlib.vedit.beans.LoginFormBean; import edu.cornell.mannlib.vitro.webapp.auth.policy.RoleBasedPolicy.AuthRole; import edu.cornell.mannlib.vitro.webapp.beans.User; import edu.cornell.mannlib.vitro.webapp.controller.Controllers; -import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreeMarkerHttpServlet; +import edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean; +import edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean.Message; +import edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean.State; import edu.cornell.mannlib.vitro.webapp.dao.UserDao; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.jena.LoginEvent; import edu.cornell.mannlib.vitro.webapp.dao.jena.LoginLogoutEvent; -public class Authenticate extends VitroHttpServlet { - private static final int DEFAULT_PORTAL_ID=1; - public static final String USER_SESSION_MAP_ATTR = "userURISessionMap"; - private UserDao userDao = null; - private static final Log log = LogFactory.getLog(Authenticate.class.getName()); +public class Authenticate extends FreeMarkerHttpServlet { + private static final Log log = LogFactory.getLog(Authenticate.class + .getName()); - public void doPost( HttpServletRequest request, HttpServletResponse response ) { - try { - HttpSession session = request.getSession(); - if(session.isNew()){ - session.setMaxInactiveInterval(300); // seconds, not milliseconds - } - userDao = ((WebappDaoFactory)session.getServletContext().getAttribute("webappDaoFactory")).getUserDao(); - LoginFormBean f = (LoginFormBean) session.getAttribute( "loginHandler" ); + /** The username field on the login form. */ + private static final String PARAMETER_USERNAME = "loginName"; - //obtain a db connection and perform a db query - //ensuring that the username exists + /** The password field on the login form. */ + private static final String PARAMETER_PASSWORD = "loginPassword"; - // JCR 20040905 passing on portal home parameter - String portalIdStr=(portalIdStr=request.getParameter("home"))==null?String.valueOf(DEFAULT_PORTAL_ID):portalIdStr; - //request.setAttribute("home",portalIdStr); + /** The new password field on the password change form. */ + private static final String PARAMETER_NEW_PASSWORD = "newPassword"; - // Build the redirect URLs - String contextPath = request.getContextPath(); - String urlParams = "?home=" + portalIdStr + "&login=block"; - String loginUrl = contextPath + Controllers.LOGIN + urlParams; - String siteAdminUrl = contextPath + Controllers.SITE_ADMIN + urlParams; + /** The confirm password field on the password change form. */ + private static final String PARAMETER_CONFIRM_PASSWORD = "confirmPassword"; - if (userDao==null) { - f.setErrorMsg("loginPassword","unable to get UserDao"); - f.setLoginStatus("no UserDao"); - response.sendRedirect(loginUrl); - return; - } + /** If they are logging in, show them this form. */ + public static final String TEMPLATE_LOGIN = "login/login.ftl"; - /* used for encoding cleartext passwords sent via http before store in database - String loginPassword = ""; - String passwordQuery = "SELECT PASSWORD('" + f.getLoginPassword() + "')"; - ResultSet ps = stmt.executeQuery( passwordQuery ); - while ( ps.next() ) { - loginPassword = ps.getString(1); - } - */ - String userEnteredPasswordAfterMd5Conversion=f.getLoginPassword(); // won't be null - if ( userEnteredPasswordAfterMd5Conversion.equals("") ) { // shouldn't get through JS form verification - f.setErrorMsg( "loginPassword","Please enter a password" ); - f.setLoginStatus("bad_password"); - response.sendRedirect(loginUrl); - return; - } + /** If they are changing their password on first login, show them this form. */ + public static final String TEMPLATE_FORCE_PASSWORD_CHANGE = "login/forcedPasswordChange.ftl"; - User user = userDao.getUserByUsername(f.getLoginName()); + public static final String BODY_LOGIN_NAME = "loginName"; + public static final String BODY_FORM_ACTION = "formAction"; + public static final String BODY_ERROR_MESSAGE = "errorMessage"; - if (user==null) { - f.setErrorMsg( "loginName","No user found with username " + f.getLoginName() ); - f.setLoginStatus("unknown_username"); - response.sendRedirect(loginUrl); - return; - } + /** If no portal is specified in the request, use this one. */ + private static final int DEFAULT_PORTAL_ID = 1; - // logic for authentication - // first check for new users (loginCount==0) - // 1) cold (have username but haven't received initial password) - // 2) initial password has been set but user mis-typed it - // 3) correctly typed initial password and oldpassword set to provided password; have to enter a different one - // 4) entered same password again - // 5) entered a new private password, and bypass this stage because logincount set to 1 - // then check for users DBA has set to require changing password (md5password is null, oldpassword is not) - // - // check password; dbMd5Password is md5password from database - if (user.getLoginCount() == 0 ) { // new user - if ( user.getMd5password() == null ) { // user is known but has not been given initial password - f.setErrorMsg( "loginPassword", "Please request a username and initial password via the link below" ); // store password in database but force immediate re-entry - f.setLoginStatus("first_login_no_password"); - } else if (!user.getMd5password().equals( userEnteredPasswordAfterMd5Conversion )) { // mis-typed CCRP-provided initial password - if ( user.getOldPassword() == null ) { // did not make it through match of initially supplied password - f.setErrorMsg( "loginPassword", "Please try entering provided password again" ); - f.setLoginStatus("first_login_mistyped"); - } else if (user.getOldPassword().equals( userEnteredPasswordAfterMd5Conversion ) ) { - f.setErrorMsg( "loginPassword", "Please pick a different password from the one provided initially" ); - f.setLoginStatus("changing_password_repeated_old"); - } else { // successfully provided different, private password - f.setErrorMsg( "loginPassword", "Please re-enter new private password for confirmation" ); - user.setMd5password(userEnteredPasswordAfterMd5Conversion); - user.setLoginCount(1); - userDao.updateUser(user); - f.setLoginStatus("changing_password"); - } - } else if (f.getLoginStatus().equals("first_login_changing_password")) { // User has been prompted to change password, but has re-entered the original one - f.setErrorMsg( "loginPassword", "Please pick a different password from the one provided initially" ); // store password in database but force immediate re-entry - user.setOldPassword(user.getMd5password()); - userDao.updateUser(user); - f.setLoginStatus("first_login_changing_password"); - } else { // entered a password that matches initial md5password in database; now force them to change it - // oldpassword could be null or not null depending on number of mistries - f.setErrorMsg( "loginPassword", "Please now choose a private password" ); // store password in database but force immediate re-entry - user.setOldPassword(user.getMd5password()); - userDao.updateUser(user); - f.setLoginStatus("first_login_changing_password"); - } - response.sendRedirect(loginUrl); - return; - } else if ( user.getMd5password()==null ) { // DBA has forced entry of a new password for user with a loginCount > 0 - if ( user.getOldPassword() != null && user.getOldPassword().equals( userEnteredPasswordAfterMd5Conversion ) ) { - f.setErrorMsg( "loginPassword", "Please pick a different password from your previous one" ); - f.setLoginStatus("changing_password_repeated_old"); - } else if (f.getLoginStatus().equals("changing_password")){ // User has been prompted to change password, but has re-entered the original one - f.setErrorMsg( "loginPassword", "Please pick a different password from the one provided initially" ); - user.setMd5password(userEnteredPasswordAfterMd5Conversion); - userDao.updateUser(user); - f.setLoginStatus("changing_password"); - } else { // User has entered provided password; now prompt to change password - f.setErrorMsg( "loginPassword", "Please re-enter new password for confirmation" ); - user.setMd5password(userEnteredPasswordAfterMd5Conversion); - userDao.updateUser(user); - f.setLoginStatus("changing_password"); - } - response.sendRedirect(loginUrl); - return; - } else if (!user.getMd5password().equals( userEnteredPasswordAfterMd5Conversion )) { - f.setErrorMsg( "loginPassword", "Incorrect password: try again"); - f.setLoginStatus("bad_password"); - f.setLoginPassword(""); // don't even reveal how many characters there were - response.sendRedirect(loginUrl); - return; - } + /** Where do we find the User/Session map in the servlet context? */ + public static final String USER_SESSION_MAP_ATTR = "userURISessionMap"; - //set the login bean properties from the database + /** + * Find out where they are in the login process, and check for progress. If + * they succeed in logging in, record the information. Show the next page. + */ + public void doPost(HttpServletRequest request, HttpServletResponse response) { - //System.out.println("authenticated; setting login status in loginformbean"); + VitroRequest vreq = new VitroRequest(request); - f.setUserURI(user.getURI()); - f.setLoginStatus( "authenticated" ); - f.setSessionId( session.getId()); - f.setLoginRole( user.getRoleURI() ); - try { - int loginRoleInt = Integer.decode(f.getLoginRole()); - if( (loginRoleInt>1) && (session.isNew()) ) { - session.setMaxInactiveInterval(32000); // set longer timeout for editors - } - } catch (Exception e) {} - // TODO : might be a problem in next line - no ID - f.setLoginUserId( -2 ); - //f.setEmailAddress ( email ); - f.setLoginPassword( "" ); - f.setErrorMsg( "loginPassword", "" ); // remove any error messages - f.setErrorMsg( "loginUsername", "" ); + User user = null; - //System.out.println("updating loginCount and modTime"); - - Map userURISessionMap = getUserURISessionMapFromContext( getServletContext() ); - userURISessionMap.put( user.getURI(), request.getSession() ); - - sendLoginNotifyEvent(new LoginEvent( user.getURI() ), getServletContext(), session); - - user.setLoginCount(user.getLoginCount()+1); - userDao.updateUser(user); + try { + // Process any input from the login form. + State entryState = getCurrentLoginState(vreq); + log.debug("State on entry: " + entryState); - if ( user.getLoginCount() == 2 ) { // first login - Calendar cal = Calendar.getInstance(); - user.setFirstTime(cal.getTime()); - userDao.updateUser(user); - } + switch (entryState) { + case LOGGING_IN: + user = checkLoginProgress(vreq); + if (user != null) { + whatNextForThisGuy(vreq, user); + } + break; + case FORCED_PASSWORD_CHANGE: + user = checkChangeProgress(vreq); + if (user != null) { + recordSuccessfulPasswordChange(vreq, user); + } + break; + default: + break; + } - /* - *If you set a postLoginRequest attribute in the session and forward to about - *then this will attempt to send the client back to the original page after the login. - */ - String forwardStr = (String) request.getSession().getAttribute("postLoginRequest"); - request.getSession().removeAttribute("postLoginRequest"); - if (forwardStr == null) { - String contextPostLoginRequest = (String) getServletContext().getAttribute("postLoginRequest"); - if (contextPostLoginRequest != null) { - forwardStr = (contextPostLoginRequest.indexOf(":") == -1) - ? request.getContextPath() + contextPostLoginRequest - : contextPostLoginRequest; - } - } - - if( AuthRole.USER.roleUri().equals( user.getRoleURI() ) ){ - /* if this is a self editor, redirect the to their page */ - List uris = userDao.getIndividualsUserMayEditAs(user.getURI()); - if( uris != null && uris.size() > 0 ){ - forwardStr = request.getContextPath() + "/individual?uri=" + URLEncoder.encode(uris.get(0), "UTF-8"); - } - } - - - if (forwardStr != null) { - response.sendRedirect(forwardStr); - } else { - response.sendRedirect(siteAdminUrl); - //RequestDispatcher rd = getServletContext().getRequestDispatcher(url); - //rd.forward(request,response); - } - } catch (Throwable t) { - log.error( t.getMessage() ); - t.printStackTrace(); - } - } + // Figure out where they should be, and redirect. + State exitState = getCurrentLoginState(vreq); + log.debug("State on exit: " + exitState); + + switch (exitState) { + case LOGGED_IN: + redirectLoggedInUser(vreq, response); + break; + default: + showLoginScreen(vreq, response); + break; + } + } catch (Exception e) { + showSystemError(e, response); + } + } + + /** + * They are logging in. Are they successful? + */ + private User checkLoginProgress(HttpServletRequest request) { + String username = request.getParameter(PARAMETER_USERNAME); + String password = request.getParameter(PARAMETER_PASSWORD); + + LoginProcessBean bean = getLoginProcessBean(request); + bean.clearMessage(); + log.trace("username=" + username + ", password=" + password + ", bean=" + + bean); + + if ((username == null) || username.isEmpty()) { + bean.setMessage(Message.NO_USERNAME); + return null; + } else { + bean.setUsername(username); + } + + User user = getUserDao(request).getUserByUsername(username); + log.trace("User is " + (user == null ? "null" : user.getURI())); + + if (user == null) { + bean.setMessage(Message.UNKNOWN_USERNAME, username); + return null; + } + + if ((password == null) || password.isEmpty()) { + bean.setMessage(Message.NO_PASSWORD); + return null; + } + + String md5Password = applyMd5Encoding(password); + + if (!md5Password.equals(user.getMd5password())) { + log.trace("Encoded passwords don't match: right=" + + user.getMd5password() + ", wrong=" + md5Password); + bean.setMessage(Message.INCORRECT_PASSWORD); + return null; + } + + return user; + } + + /** + * Successfully applied username and password. Are we forcing a password + * change, or is this guy logged in? + */ + private void whatNextForThisGuy(HttpServletRequest request, User user) { + if (user.getLoginCount() == 0) { + log.debug("Forcing first-time password change"); + LoginProcessBean bean = getLoginProcessBean(request); + bean.setState(State.FORCED_PASSWORD_CHANGE); + } else { + recordLoginInfo(request, user); + } + } + + /** + * They are changing password. Are they successful? + */ + private User checkChangeProgress(HttpServletRequest request) { + String newPassword = request.getParameter(PARAMETER_NEW_PASSWORD); + String confirm = request.getParameter(PARAMETER_CONFIRM_PASSWORD); + LoginProcessBean bean = getLoginProcessBean(request); + bean.clearMessage(); + log.trace("newPassword=" + newPassword + ", confirm=" + confirm + + ", bean=" + bean); + + if ((newPassword == null) || newPassword.isEmpty()) { + bean.setMessage(Message.NO_NEW_PASSWORD); + return null; + } + + if (!newPassword.equals(confirm)) { + bean.setMessage(Message.MISMATCH_PASSWORD); + return null; + } + + if ((newPassword.length() < User.MIN_PASSWORD_LENGTH) + || (newPassword.length() > User.MAX_PASSWORD_LENGTH)) { + bean.setMessage(Message.PASSWORD_LENGTH, User.MIN_PASSWORD_LENGTH, + User.MAX_PASSWORD_LENGTH); + return null; + } + + User user = getUserDao(request).getUserByUsername(bean.getUsername()); + log.trace("User is " + (user == null ? "null" : user.getURI())); + + if (user == null) { + throw new IllegalStateException( + "Changing password but bean has no user: '" + + bean.getUsername() + "'"); + } + + String md5NewPassword = applyMd5Encoding(newPassword); + log.trace("Old password: " + user.getMd5password() + ", new password: " + + md5NewPassword); + + if (md5NewPassword.equals(user.getMd5password())) { + bean.setMessage(Message.USING_OLD_PASSWORD); + return null; + } + + return user; + } + + /** + * Store the changed password. They're not logged in yet, but they no longer + * need to change their password. + */ + private void recordSuccessfulPasswordChange(HttpServletRequest request, + User user) { + String newPassword = request.getParameter(PARAMETER_NEW_PASSWORD); + String md5NewPassword = applyMd5Encoding(newPassword); + user.setOldPassword(user.getMd5password()); + user.setMd5password(md5NewPassword); + user.setLoginCount(user.getLoginCount() + 1); + getUserDao(request).updateUser(user); + log.debug("Completed first-time password change."); + + LoginProcessBean bean = getLoginProcessBean(request); + bean.setState(State.LOGGING_IN); + bean.setMessage(Message.PASSWORD_CHANGE_SAVED); + } + + /** + * The user provided the correct information, and changed the password if + * that was required. Record that they have logged in. + */ + private void recordLoginInfo(HttpServletRequest request, User user) { + log.debug("Completed login."); + + HttpSession session = request.getSession(); + + // Put the login info into the session. + LoginFormBean lfb = new LoginFormBean(); + lfb.setUserURI(user.getURI()); + lfb.setLoginStatus("authenticated"); + lfb.setSessionId(session.getId()); + lfb.setLoginRole(user.getRoleURI()); + lfb.setLoginRemoteAddr(request.getRemoteAddr()); + lfb.setLoginName(user.getUsername()); + session.setAttribute("loginHandler", lfb); + + // Remove the login process info from the session. + session.removeAttribute(LoginProcessBean.SESSION_ATTRIBUTE); + + // Record the login on the user. + user.setLoginCount(user.getLoginCount() + 1); + if (user.getFirstTime() == null) { // first login + user.setFirstTime(new Date()); + } + getUserDao(request).updateUser(user); + + // Set the timeout limit on the session - editors, etc, get more. + session.setMaxInactiveInterval(300); // seconds, not milliseconds + try { + if ((int) Integer.decode(lfb.getLoginRole()) > 1) { + session.setMaxInactiveInterval(32000); + } + } catch (NumberFormatException e) { + // No problem - leave it at the default. + } + + // Record the user in the user/Session map. + Map userURISessionMap = getUserURISessionMapFromContext(getServletContext()); + userURISessionMap.put(user.getURI(), request.getSession()); + + // Notify the other users of this model. + sendLoginNotifyEvent(new LoginEvent(user.getURI()), + getServletContext(), session); + + } + + /** + * User is in the login process. Show them the login screen. + */ + private void showLoginScreen(VitroRequest vreq, HttpServletResponse response) + throws IOException { + response.sendRedirect(getLoginScreenUrl(vreq)); + return; + } + + /** + * User is logged in. They might go to: + *
    + *
  • A one-time redirect, stored in the session, if they had tried to + * bookmark to a page that requires login.
  • + *
  • An application-wide redirect, stored in the servlet context.
  • + *
  • Their home page, if they are a self-editor.
  • + *
  • The site admin page.
  • + *
+ */ + private void redirectLoggedInUser(HttpServletRequest request, + HttpServletResponse response) throws IOException, + UnsupportedEncodingException { + // Did they have a one-time redirect stored on the session? + String sessionRedirect = (String) request.getSession().getAttribute( + "postLoginRequest"); + if (sessionRedirect != null) { + request.getSession().removeAttribute("postLoginRequest"); + log.debug("User is logged in. Redirect by session to " + + sessionRedirect); + response.sendRedirect(sessionRedirect); + return; + } + + // Is there a login-redirect stored in the application as a whole? + // It could lead to another page in this app, or to any random URL. + String contextRedirect = (String) getServletContext().getAttribute( + "postLoginRequest"); + if (contextRedirect != null) { + log.debug("User is logged in. Redirect by application to " + + contextRedirect); + if (contextRedirect.indexOf(":") == -1) { + response.sendRedirect(request.getContextPath() + + contextRedirect); + } else { + response.sendRedirect(contextRedirect); + } + return; + } + + // If the user is a self-editor, send them to their home page. + User user = getLoggedInUser(request); + if (AuthRole.USER.roleUri().equals(user.getRoleURI())) { + UserDao userDao = getUserDao(request); + if (userDao != null) { + List uris = userDao.getIndividualsUserMayEditAs(user + .getURI()); + if (uris != null && uris.size() > 0) { + log.debug("User is logged in. Redirect as self-editor to " + + sessionRedirect); + String userHomePage = request.getContextPath() + + "/individual?uri=" + + URLEncoder.encode(uris.get(0), "UTF-8"); + log.debug("User is logged in. Redirect as self-editor to " + + sessionRedirect); + response.sendRedirect(userHomePage); + return; + } + } + } + + // If nothing else applies, send them to the Site Admin page. + log.debug("User is logged in. Redirect to site admin page."); + response.sendRedirect(getSiteAdminUrl(request)); + } + + /** + * There has been an unexpected exception. Complain mightily. + */ + private void showSystemError(Exception e, HttpServletResponse response) { + log.error("Unexpected error in login process" + e); + try { + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } catch (IOException e1) { + log.error(e1, e1); + } + } + + /** + * Where are we in the process? Logged in? Not? Somewhere in between? + */ + private State getCurrentLoginState(HttpServletRequest request) { + HttpSession session = request.getSession(false); + if (session == null) { + return State.NOWHERE; + } + + LoginFormBean lfb = (LoginFormBean) session + .getAttribute("loginHandler"); + if ((lfb != null) && (lfb.getLoginStatus().equals("authenticated"))) { + return State.LOGGED_IN; + } + + return getLoginProcessBean(request).getState(); + } + + /** + * What user are we logged in as? + */ + private User getLoggedInUser(HttpServletRequest request) { + UserDao userDao = getUserDao(request); + if (userDao == null) { + return null; + } + + HttpSession session = request.getSession(false); + if (session == null) { + return null; + } + + LoginFormBean lfb = (LoginFormBean) session + .getAttribute("loginHandler"); + if (lfb == null) { + log.debug("getLoggedInUser: not logged in"); + return null; + } + + return userDao.getUserByUsername(lfb.getLoginName()); + } + + /** + * Get a reference to the {@link UserDao}, or null. + */ + private UserDao getUserDao(HttpServletRequest request) { + HttpSession session = request.getSession(false); + if (session == null) { + return null; + } + + ServletContext servletContext = session.getServletContext(); + WebappDaoFactory wadf = (WebappDaoFactory) servletContext + .getAttribute("webappDaoFactory"); + if (wadf == null) { + log.error("getUserDao: no WebappDaoFactory"); + return null; + } + + UserDao userDao = wadf.getUserDao(); + if (userDao == null) { + log.error("getUserDao: no UserDao"); + } + + return userDao; + } + + /** What's the URL for the login screen? */ + private String getLoginScreenUrl(HttpServletRequest request) { + String contextPath = request.getContextPath(); + String urlParams = "?home=" + getPortalIdString(request) + + "&login=block"; + return contextPath + Controllers.LOGIN + urlParams; + } + + /** What's the URL for the site admin screen? */ + private String getSiteAdminUrl(HttpServletRequest request) { + String contextPath = request.getContextPath(); + String urlParams = "?home=" + getPortalIdString(request) + + "&login=block"; + return contextPath + Controllers.SITE_ADMIN + urlParams; + } + + /** + * What portal are we currently in? + */ + private String getPortalIdString(HttpServletRequest request) { + String portalIdParameter = request.getParameter("home"); + if (portalIdParameter == null) { + return String.valueOf(DEFAULT_PORTAL_ID); + } else { + return portalIdParameter; + } + } + + /** + * How is the login process coming along? + */ + private LoginProcessBean getLoginProcessBean(HttpServletRequest request) { + HttpSession session = request.getSession(); + + LoginProcessBean bean = (LoginProcessBean) session + .getAttribute(LoginProcessBean.SESSION_ATTRIBUTE); + + if (bean == null) { + bean = new LoginProcessBean(); + session.setAttribute(LoginProcessBean.SESSION_ATTRIBUTE, bean); + } + + return bean; + } + + /** + * Encode this password for storage in the database. Apply an MD5 encoding, + * and store the result as a string of hex digits. + */ + private String applyMd5Encoding(String password) { + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] digest = md.digest(password.getBytes()); + char[] hexChars = Hex.encodeHex(digest); + return new String(hexChars).toUpperCase(); + } catch (NoSuchAlgorithmException e) { + // This can't happen with a normal Java runtime. + throw new RuntimeException(e); + } + } + + // ---------------------------------------------------------------------- + // Public utility methods. + // ---------------------------------------------------------------------- + + /** + * The servlet context should contain a map from User URIs to + * {@link HttpSession}s. Get a reference to it, creating it if necessary. + */ + @SuppressWarnings("unchecked") + public static Map getUserURISessionMapFromContext( + ServletContext ctx) { + Map m = (Map) ctx + .getAttribute(USER_SESSION_MAP_ATTR); + if (m == null) { + m = new HashMap(); + ctx.setAttribute(USER_SESSION_MAP_ATTR, m); + } + return m; + } + + /** + * Let everyone know that somebody has logged in or logged out. + */ + public static void sendLoginNotifyEvent(LoginLogoutEvent event, + ServletContext context, HttpSession session) { + if (event == null) { + log.warn("Unable to notify audit model of login " + + "because a null event was passed"); + return; + } + + OntModel jenaOntModel = (OntModel) session.getAttribute("jenaOntModel"); + if (jenaOntModel == null) { + jenaOntModel = (OntModel) context.getAttribute("jenaOntModel"); + } + if (jenaOntModel == null) { + log.error("Unable to notify audit model of login event " + + "because no model could be found"); + return; + } + + jenaOntModel.getBaseModel().notifyEvent(event); + } - public static void sendLoginNotifyEvent(LoginLogoutEvent event, ServletContext context, HttpSession session){ - Object sessionOntModel = null; - if( session != null ) - sessionOntModel = session.getAttribute("jenaOntModel"); - Object contextOntModel = null; - if( context != null ) - contextOntModel = context.getAttribute("jenaOntModel"); - - OntModel jenaOntModel = - ( (sessionOntModel != null && sessionOntModel instanceof OntModel) - ? (OntModel)sessionOntModel: (OntModel) context.getAttribute("jenaOntModel") ); - - if( jenaOntModel == null ){ - log.error( "Unable to notify audit model of login event because no model could be found"); - } else { - if( event == null ){ - log.warn("Unable to notify audit model of login because a null event was passed"); - }else{ - jenaOntModel.getBaseModel().notifyEvent( event ); - } - } - } - - public static Map getUserURISessionMapFromContext( ServletContext ctx ) { - Map m = (Map) ctx.getAttribute( USER_SESSION_MAP_ATTR ); - if ( m == null ) { - m = new HashMap(); - ctx.setAttribute( USER_SESSION_MAP_ATTR, m ); - } - return m; - } - } - diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/UserEditController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/UserEditController.java index 0c85c9bed..91b52fa0b 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/UserEditController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/UserEditController.java @@ -68,7 +68,7 @@ public class UserEditController extends BaseEditController { } ArrayList results = new ArrayList(); - results.add("User"); + results.add("Email address"); results.add("first name"); results.add("last name"); results.add("login count"); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/login/LoginProcessBean.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/login/LoginProcessBean.java new file mode 100644 index 000000000..c491f153b --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/login/LoginProcessBean.java @@ -0,0 +1,139 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.login; + +import java.text.MessageFormat; +import java.util.Arrays; + +/** + * Where are we in the process of logging on? What message should we show to the + * user? + */ +public class LoginProcessBean { + private static Object[] NO_ARGUMENTS = new Object[0]; + + public static final String SESSION_ATTRIBUTE = LoginProcessBean.class + .getName(); + + public enum State { + NOWHERE, LOGGING_IN, FORCED_PASSWORD_CHANGE, LOGGED_IN + } + + private enum MLevel { + NONE, INFO, ERROR + } + + public enum Message { + NO_MESSAGE("", MLevel.NONE), + + PASSWORD_CHANGE_SAVED("Your password has been saved.
" + + "Please log in.", MLevel.INFO), + + NO_USERNAME("Please enter your email address.", MLevel.ERROR), + + NO_PASSWORD("Please enter your password.", MLevel.ERROR), + + UNKNOWN_USERNAME("The email or password you entered is incorrect.", + MLevel.ERROR), + + INCORRECT_PASSWORD("The email or password you entered is incorrect.", + MLevel.ERROR), + + NO_NEW_PASSWORD("Please enter your new password.", MLevel.ERROR), + + MISMATCH_PASSWORD("The passwords entered do not match.", MLevel.ERROR), + + PASSWORD_LENGTH( + "Please enter a password between {0} and {1} characters long", + MLevel.ERROR), + + USING_OLD_PASSWORD("Please choose a different password from the " + + "temporary one provided initially.", MLevel.ERROR); + + private final String format; + private final MLevel messageLevel; + + Message(String format, MLevel messageLevel) { + this.format = format; + this.messageLevel = messageLevel; + } + + String getFormat() { + return this.format; + } + + MLevel getMessageLevel() { + return this.messageLevel; + } + + String formatMessage(Object[] args) { + return new MessageFormat(this.format).format(args); + } + } + + /** Where are we in the process? */ + private State currentState = State.NOWHERE; + + /** What message should we display on the screen? */ + private Message message = Message.NO_MESSAGE; + + /** What arguments are needed to format the message? */ + private Object[] messageArguments = NO_ARGUMENTS; + + /** + * What username was submitted to the form? This isn't just for display -- + * if they are changing passwords, we need to remember who it is. + */ + private String username = ""; + + public void setState(State newState) { + this.currentState = newState; + } + + public State getState() { + return currentState; + } + + public void clearMessage() { + this.message = Message.NO_MESSAGE; + this.messageArguments = NO_ARGUMENTS; + } + + public void setMessage(Message message, Object... args) { + this.message = message; + this.messageArguments = args; + } + + public String getInfoMessage() { + if (message.getMessageLevel() == MLevel.INFO) { + return message.formatMessage(messageArguments); + } else { + return ""; + } + } + + public String getErrorMessage() { + if (message.getMessageLevel() == MLevel.ERROR) { + return message.formatMessage(messageArguments); + } else { + return ""; + } + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + @Override + public String toString() { + return "LoginProcessBean[state=" + currentState + ", message=" + + message + ", messageArguments=" + + Arrays.deepToString(messageArguments) + ", username=" + + username + "]"; + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/login/LoginTemplateHelper.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/login/LoginTemplateHelper.java new file mode 100644 index 000000000..6bcda3b7b --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/login/LoginTemplateHelper.java @@ -0,0 +1,225 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.login; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import edu.cornell.mannlib.vedit.beans.LoginFormBean; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.edit.Authenticate; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreeMarkerHttpServlet; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; +import edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean.State; +import freemarker.template.Configuration; + +/** + * A temporary means of displaying the Login templates within the SiteAdmin + * form. + * + * This class contains stuff that I swiped from {@link Authenticate}. The base + * class, {@link LoginTemplateHelperBase}, contains stuff that I swiped from + * {@link FreeMarkerHttpServlet}. + */ +public class LoginTemplateHelper extends LoginTemplateHelperBase { + private static final Log log = LogFactory.getLog(LoginTemplateHelper.class); + + /** If they are logging in, show them this form. */ + public static final String TEMPLATE_LOGIN = "login/login.ftl"; + + /** If they are changing their password on first login, show them this form. */ + public static final String TEMPLATE_FORCE_PASSWORD_CHANGE = "login/forcedPasswordChange.ftl"; + + public static final String BODY_LOGIN_NAME = "loginName"; + public static final String BODY_FORM_ACTION = "formAction"; + public static final String BODY_INFO_MESSAGE = "infoMessage"; + public static final String BODY_ERROR_MESSAGE = "errorMessage"; + public static final String BODY_ALERT_ICON_URL = "alertImageUrl"; + + /** Use this icon for an info message. */ + public static final String URL_INFO_ICON = "/images/iconAlert.png"; + + /** Use this icon for an error message. */ + public static final String URL_ERROR_ICON = "/images/iconAlert.png"; + + /** If no portal is specified in the request, use this one. */ + private static final int DEFAULT_PORTAL_ID = 1; + + public LoginTemplateHelper(HttpServletRequest req) { + super(req); + } + + public String showLoginPage(HttpServletRequest request) { + try { + VitroRequest vreq = new VitroRequest(request); + + State state = getCurrentLoginState(vreq); + log.debug("State on exit: " + state); + + switch (state) { + case LOGGED_IN: + return ""; + case FORCED_PASSWORD_CHANGE: + return doTemplate(vreq, showPasswordChangeScreen(vreq)); + default: + return doTemplate(vreq, showLoginScreen(vreq)); + } + } catch (Exception e) { + log.error(e); + return "

Internal server error:
" + e + "

"; + } + } + + /** + * User is just starting the login process. Be sure that we have a + * {@link LoginProcessBean} with the correct status. Show them the login + * screen. + */ + private TemplateResponseValues showLoginScreen(VitroRequest vreq) + throws IOException { + LoginProcessBean bean = getLoginProcessBean(vreq); + bean.setState(State.LOGGING_IN); + log.trace("Going to login screen: " + bean); + + TemplateResponseValues trv = new TemplateResponseValues(TEMPLATE_LOGIN); + trv.put(BODY_FORM_ACTION, getAuthenticateUrl(vreq)); + trv.put(BODY_LOGIN_NAME, bean.getUsername()); + + String infoMessage = bean.getInfoMessage(); + if (!infoMessage.isEmpty()) { + trv.put(BODY_INFO_MESSAGE, infoMessage); + trv.put(BODY_ALERT_ICON_URL, UrlBuilder.getUrl(URL_INFO_ICON)); + } + String errorMessage = bean.getErrorMessage(); + if (!errorMessage.isEmpty()) { + trv.put(BODY_ERROR_MESSAGE, errorMessage); + trv.put(BODY_ALERT_ICON_URL, UrlBuilder.getUrl(URL_ERROR_ICON)); + } + return trv; + } + + /** + * The user has given the correct password, but now they are required to + * change it. + */ + private TemplateResponseValues showPasswordChangeScreen(VitroRequest vreq) { + LoginProcessBean bean = getLoginProcessBean(vreq); + bean.setState(State.FORCED_PASSWORD_CHANGE); + log.trace("Going to password change screen: " + bean); + + TemplateResponseValues trv = new TemplateResponseValues( + TEMPLATE_FORCE_PASSWORD_CHANGE); + trv.put(BODY_FORM_ACTION, getAuthenticateUrl(vreq)); + + String errorMessage = bean.getErrorMessage(); + if (!errorMessage.isEmpty()) { + trv.put(BODY_ERROR_MESSAGE, errorMessage); + trv.put(BODY_ALERT_ICON_URL, UrlBuilder.getUrl(URL_ERROR_ICON)); + } + return trv; + } + + /** + * We processed a response, and want to show a template. + */ + private String doTemplate(VitroRequest vreq, TemplateResponseValues values) { + // Set it up like FreeMarkerHttpServlet.doGet() would do. + Configuration config = getConfig(vreq); + Map sharedVariables = getSharedVariables(vreq); + Map root = new HashMap(sharedVariables); + Map body = new HashMap(sharedVariables); + setUpRoot(vreq, root); + + // Add the values that we got, and merge to the template. + body.putAll(values.getBodyMap()); + return mergeBodyToTemplate(values.getTemplateName(), body, config); + } + + /** + * Where are we in the process? Logged in? Not? Somewhere in between? + */ + private State getCurrentLoginState(HttpServletRequest request) { + HttpSession session = request.getSession(false); + if (session == null) { + return State.NOWHERE; + } + + LoginFormBean lfb = (LoginFormBean) session + .getAttribute("loginHandler"); + if ((lfb != null) && (lfb.getLoginStatus().equals("authenticated"))) { + return State.LOGGED_IN; + } + + return getLoginProcessBean(request).getState(); + } + + /** + * How is the login process coming along? + */ + private LoginProcessBean getLoginProcessBean(HttpServletRequest request) { + HttpSession session = request.getSession(); + + LoginProcessBean bean = (LoginProcessBean) session + .getAttribute(LoginProcessBean.SESSION_ATTRIBUTE); + + if (bean == null) { + bean = new LoginProcessBean(); + session.setAttribute(LoginProcessBean.SESSION_ATTRIBUTE, bean); + } + + return bean; + } + + /** What's the URL for this servlet? */ + private String getAuthenticateUrl(HttpServletRequest request) { + String contextPath = request.getContextPath(); + String urlParams = "?home=" + getPortalIdString(request) + + "&login=block"; + return contextPath + "/authenticate" + urlParams; + } + + /** + * What portal are we currently in? + */ + private String getPortalIdString(HttpServletRequest request) { + String portalIdParameter = request.getParameter("home"); + if (portalIdParameter == null) { + return String.valueOf(DEFAULT_PORTAL_ID); + } else { + return portalIdParameter; + } + } + + /** + * Holds the name of the template and the map of values. + */ + private static class TemplateResponseValues { + private final String templateName; + private final Map bodyMap = new HashMap(); + + public TemplateResponseValues(String templateName) { + this.templateName = templateName; + } + + public TemplateResponseValues put(String key, Object value) { + this.bodyMap.put(key, value); + return this; + } + + public Map getBodyMap() { + return Collections.unmodifiableMap(this.bodyMap); + } + + public String getTemplateName() { + return this.templateName; + } + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/login/LoginTemplateHelperBase.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/login/LoginTemplateHelperBase.java new file mode 100644 index 000000000..6eac3cf89 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/login/LoginTemplateHelperBase.java @@ -0,0 +1,27 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.login; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; + +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreeMarkerHttpServlet; + +/** + * A temporary means of displaying the Login templates within the SiteAdmin + * form. + * + * The constructor insures that the ServletContext is set. + */ +public class LoginTemplateHelperBase extends FreeMarkerHttpServlet { + private final ServletContext servletContext; + + LoginTemplateHelperBase(HttpServletRequest req) { + this.servletContext = req.getSession().getServletContext(); + } + + public ServletContext getServletContext() { + return servletContext; + } + +} diff --git a/webapp/web/images/iconAlert.png b/webapp/web/images/iconAlert.png new file mode 100644 index 0000000000000000000000000000000000000000..27803e2fbfb38737de616958f4e735e55f5aaca4 GIT binary patch literal 1478 zcmV;%1v&bOP)1=3eY3WF%QnS~tT}!++9~d7WzbNo@ ztKYr>b}j~XHU@rS6?jf-5(J^6y}doq-QCT-764^sWfaG8-@0wvKx=6LRYd|6JR}WX zTNJ12S5Bw%lM5FvcyHXeLFes+uWADW0~c*pI!LshUkt;aV~fCB82Gd{01k@`0`GDr zlF2W4o}ac_tr6TJ9T@|qrKOa`V(IbChX#PcJ6wV)@)QX>T~LuX ztDNZIbWjL_*EYe)Cpa`itJmv&_r!@4!l3|+jg1lQFT45YrVv86-;+JJz`^D)qe3A} zkxcnM`a=z7$)dejc(s$zbcd6dQTv!K0EH7_!D5@aCQxKGn89z!FtD*n5Vcvt!k2!( zzakh6+71MOXpf$Mxqw^OH8kR$bbmoM*JQ?u3=m($z+1rYG88J0NnUsdnfSQ2wzlNz z)vIjY0I)Wo_9>Bgw@$BOnxV+efz?8z{aLWmae(cA08$(HP0oPflnoG-5HUpy`a&i8 zf;}$)PoF-`*xth~n_7dK)|oKqcJLUEoBsmDW&zTYAslOwilsnFLQ&!YP>OU4L7c~k zIEgH9`v$-;Oh*A96FCh-Pmbw5wTU)fL#mPH=nTAJU4m1^vMyLnW`yd`RE7mciGnBj z2at&H`F!tTigxY`02Z7wq`y;4{EpfowefkhE$K^`byjsCiUf8ZGE8j8C0)3(BRpjS za!bDgtx6@B7aCnISK#*T+uWYDpuD^sWmDgY)BJaB3>N4RWy z_s-$xPxI!!iZ_|8337$2J0KF^*}6}{@*@OMi8m}b#-kL4`O$@Yz{}+67XqHfXT6? z`OKtTeO%@>-YYqFH_ar!Fn;d*j6@c>FA9M`fIWNmEVV0uXf*nZ)mnIOo^ELNXyfRJ zn|j=nP9Yn#;b`PZ8To<2IiqC3?R1<2!M=l<3&~qg+f~s6BAo=b8`tId`|{;T2D_8xdqcYiwFOUV_8<4nVC^;-n^;p g`Db(-?LPqq0IX#mD7;{E;s5{u07*qoM6N<$f>!FgXaE2J literal 0 HcmV?d00001 diff --git a/webapp/web/siteAdmin/loginForm.jsp b/webapp/web/siteAdmin/loginForm.jsp index 090f67123..c5754a7ea 100644 --- a/webapp/web/siteAdmin/loginForm.jsp +++ b/webapp/web/siteAdmin/loginForm.jsp @@ -2,120 +2,14 @@ <%-- Included in siteAdmin/main.jsp to handle login/logout form and processing --%> +<%@ page import="edu.cornell.mannlib.vitro.webapp.controller.login.LoginTemplateHelper" %> +<%@ page import="edu.cornell.mannlib.vitro.webapp.controller.VitroRequest" %> -<%@ page import="edu.cornell.mannlib.vitro.webapp.beans.Portal" %> -<%@ page import="edu.cornell.mannlib.vitro.webapp.controller.Controllers" %> - - - - - - -<% - int securityLevel = loginHandler.ANYBODY; - String loginStatus = loginHandler.getLoginStatus(); - if ( loginStatus.equals("authenticated")) { -%> -
<% - } else { + String themeDir = new VitroRequest(request).getPortal().getThemeDir().replaceAll("/$", ""); %> -
-<% - } - if ( loginStatus.equals("authenticated")) { - - // test whether session is still valid - String currentSessionId = session.getId(); - String storedSessionId = loginHandler.getSessionId(); - - if ( currentSessionId.equals( storedSessionId ) ) { - String currentRemoteAddrStr = request.getRemoteAddr(); - String storedRemoteAddr = loginHandler.getLoginRemoteAddr(); - securityLevel = Integer.parseInt( loginHandler.getLoginRole() ); - if ( currentRemoteAddrStr.equals( storedRemoteAddr ) ) { -%> -
- - Logged in as - -
- -<% - } else { -%> - ${loginFormTitle} - (IP address has changed)
-<% - loginHandler.setLoginStatus("logged out"); - } - - } else { - loginHandler.setLoginStatus("logged out"); -%> - ${loginFormTitle} - (session has expired)
- -<% - } - - } else { /* not thrown out by coming from different IP address or expired session; check login status returned by authenticate.java */ -%> -

Please log in

-<% - if ( loginStatus.equals("logged out")) { %> - (currently logged out) -<% } else if ( loginStatus.equals("bad_password")) { %> - (password incorrect)
-<% } else if ( loginStatus.equals("unknown_username")) { %> - (unknown username)
-<% } else if ( loginStatus.equals("first_login_no_password")) { %> - (1st login; need to request initial password below) -<% } else if ( loginStatus.equals("first_login_mistyped")) { %> - (1st login; initial password entered incorrectly) -<% } else if ( loginStatus.equals("first_login_changing_password")) { %> - (1st login; changing to new private password) -<% } else if ( loginStatus.equals("changing_password_repeated_old")) { %> - (changing to a different password) -<% } else if ( loginStatus.equals("changing_password")) { %> - (changing to new password) -<% } else if ( loginStatus.equals("none")) { %> - (new session)
-<% } else { %> - Status unrecognized: <%=loginStatus.replace("_", " ")%>
-<% } %> - -
- - -<% - if ( loginStatus.equals("bad_password") || loginStatus.equals("first_login_no_password") - || loginStatus.equals("first_login_mistyped") || loginStatus.equals("first_login_changing_password") - || loginStatus.equals("changing_password_repeated_old") || loginStatus.equals("changing_password") ) { %> -
-<% } else { %> -
-<% if ( loginStatus.equals("unknown_username") ) { %> - Unknown username -<% } - } -%> - -
+ -<% String passwordError=loginHandler.getErrorMsg("loginPassword"); - if (passwordError!=null && !passwordError.equals("")) {%> - <%=passwordError%> -<% } %> +<%= new LoginTemplateHelper(request).showLoginPage(request) %> - -
-<% } %> - -
diff --git a/webapp/web/siteAdmin/siteAdminMain.jsp b/webapp/web/siteAdmin/siteAdminMain.jsp index 7d2370baa..a4bb30854 100644 --- a/webapp/web/siteAdmin/siteAdminMain.jsp +++ b/webapp/web/siteAdmin/siteAdminMain.jsp @@ -17,8 +17,14 @@ Portal portal = (Portal) request.getAttribute("portalBean"); final String DEFAULT_SEARCH_METHOD = "fulltext"; /* options are fulltext/termlike */ + int securityLevel = loginHandler.ANYBODY; + String loginStatus = loginHandler.getLoginStatus(); + if ( loginStatus.equals("authenticated")) { + securityLevel = Integer.parseInt( loginHandler.getLoginRole() ); + } %> +
diff --git a/webapp/web/siteAdmin/siteAdminScripts.jsp b/webapp/web/siteAdmin/siteAdminScripts.jsp index 6eb4d9850..c14d4b25a 100644 --- a/webapp/web/siteAdmin/siteAdminScripts.jsp +++ b/webapp/web/siteAdmin/siteAdminScripts.jsp @@ -13,14 +13,10 @@ function isValidLogin( theForm ) { theForm.loginName.focus(); return false; } - if ( isEmptyOrWrongLength( theForm.loginPassword.value)) { + if ( isEmptyPassword( theForm.loginPassword.value)) { theForm.loginPassword.focus(); return false; } - - //alert("theForm.loginPassword.value=" + theForm.loginPassword.value ); - theForm.loginPassword.value = calcMD5( theForm.loginPassword.value ); - //alert("theForm.loginPassword.value=" + theForm.loginPassword.value ); return true; } @@ -32,15 +28,39 @@ function isEmpty( aStr ) { return false; } -function isEmptyOrWrongLength( aStr ) { +function isEmptyPassword( aStr ) { if ( aStr.length == 0 ) { alert("Please enter a password to log in"); return true; - } else if ( aStr.length < <%=User.MIN_PASSWORD_LENGTH%> || aStr.length > <%=User.MAX_PASSWORD_LENGTH%>) { - alert("Please enter a password between 6 and 12 characters long"); - return true; } return false; +} + +function isReasonableNewPassword( theForm ) { + if ( isWrongLengthPassword( theForm.newPassword.value)) { + theForm.newPassword.focus(); + return false; + } + if ( isMismatchedPasswords( theForm.newPassword.value, theForm.confirmPassword.value)) { + theForm.newPassword.focus(); + return false; + } +} + +function isWrongLengthPassword( aStr ) { + if ( aStr.length < <%=User.MIN_PASSWORD_LENGTH%> || aStr.length > <%=User.MAX_PASSWORD_LENGTH%>) { + alert("Please enter a password between <%=User.MIN_PASSWORD_LENGTH%> and <%=User.MAX_PASSWORD_LENGTH%> characters long"); + return true; + } + return false; +} + +function isMismatchedPasswords( one, two ) { + if ( one != two ) { + alert("Passwords do not match"); + return true; + } + return false; } //Give initial focus to the password or username field diff --git a/webapp/web/templates/edit/specific/user_retry.jsp b/webapp/web/templates/edit/specific/user_retry.jsp index 85ce9679e..7e907711b 100644 --- a/webapp/web/templates/edit/specific/user_retry.jsp +++ b/webapp/web/templates/edit/specific/user_retry.jsp @@ -6,7 +6,7 @@ - User Name*
+ Email address*
diff --git a/webapp/web/templates/freemarker/body/login/forcedPasswordChange.ftl b/webapp/web/templates/freemarker/body/login/forcedPasswordChange.ftl new file mode 100644 index 000000000..16029de3c --- /dev/null +++ b/webapp/web/templates/freemarker/body/login/forcedPasswordChange.ftl @@ -0,0 +1,27 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#-- Crop the replacement main image for an Individual, to produce a thumbnail. --> + +

Forced password change

+ +${stylesheets.addFromTheme("/login.css")} + +
+

Create Your New Password

+ + <#if errorMessage??> +
+

${errorMessage}

+
+ + +
+ + + + +
+ +
+
+ diff --git a/webapp/web/templates/freemarker/body/login/login.ftl b/webapp/web/templates/freemarker/body/login/login.ftl new file mode 100644 index 000000000..65dc398ee --- /dev/null +++ b/webapp/web/templates/freemarker/body/login/login.ftl @@ -0,0 +1,29 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#-- Crop the replacement main image for an Individual, to produce a thumbnail. --> + +${stylesheets.addFromTheme("/login.css")} + +
+

Log in

+ + <#if infoMessage??> +

${infoMessage}

+ + + <#if errorMessage??> +
+

${errorMessage}

+
+ + +
+ + + + +
+ +
+
+