From db304c4f522a5a11e689b681e086af59426ba6e4 Mon Sep 17 00:00:00 2001 From: jeb228 Date: Thu, 4 Nov 2010 19:01:23 +0000 Subject: [PATCH] NIHVIVO-1207 Factor out the model-related stuff from Authenticate into Authenticator. --- .../authenticate/Authenticator.java | 84 +++++++ .../authenticate/BasicAuthenticator.java | 217 ++++++++++++++++++ .../webapp/controller/edit/Authenticate.java | 178 ++++---------- .../controller/edit/AuthenticateTest.java | 30 ++- 4 files changed, 369 insertions(+), 140 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/Authenticator.java create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/BasicAuthenticator.java diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/Authenticator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/Authenticator.java new file mode 100644 index 000000000..65f17d7eb --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/Authenticator.java @@ -0,0 +1,84 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.authenticate; + +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import edu.cornell.mannlib.vitro.webapp.beans.User; + +/** + * The tool that a login process will use to interface with the user records in + * the model (or wherever). + */ +public abstract class Authenticator { + // ---------------------------------------------------------------------- + // The factory + // + // Unit tests can replace the factory to get a stub class instead. + // Note: this can only work because the factory value is not final. + // ---------------------------------------------------------------------- + + public static interface AuthenticatorFactory { + Authenticator newInstance(HttpServletRequest request); + } + + private static AuthenticatorFactory factory = new AuthenticatorFactory() { + @Override + public Authenticator newInstance(HttpServletRequest request) { + return new BasicAuthenticator(request); + } + }; + + public static Authenticator getInstance(HttpServletRequest request) { + return factory.newInstance(request); + } + + // ---------------------------------------------------------------------- + // The interface. + // ---------------------------------------------------------------------- + + /** Maximum inactive interval for a ordinary logged-in session, in seconds. */ + public static final int LOGGED_IN_TIMEOUT_INTERVAL = 300; + + /** Maximum inactive interval for a editor (or better) session, in seconds. */ + public static final int PRIVILEGED_TIMEOUT_INTERVAL = 32000; + + /** + * Does a user by this name exist? + */ + public abstract boolean isExistingUser(String username); + + /** + * Does a user by this name have this password? + */ + public abstract boolean isCurrentPassword(String username, + String clearTextPassword); + + /** + * Get the user with this name, or null if no such user exists. + */ + public abstract User getUserByUsername(String username); + + /** + * Return a list of URIs of the people that this user is allowed to edit. + */ + public abstract List asWhomMayThisUserEdit(User user); + + /** + * Record a new password for the user. + */ + public abstract void recordNewPassword(User user, + String newClearTextPassword); + + /** + * Record that the user has logged in. + */ + public abstract void recordSuccessfulLogin(User user); + + /** + * Set the login status in the session. + */ + public abstract void setLoggedIn(User user); +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/BasicAuthenticator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/BasicAuthenticator.java new file mode 100644 index 000000000..8ed97663b --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/BasicAuthenticator.java @@ -0,0 +1,217 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.authenticate; + +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletContext; +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.vedit.beans.LoginStatusBean; +import edu.cornell.mannlib.vitro.webapp.beans.User; +import edu.cornell.mannlib.vitro.webapp.controller.edit.Authenticate; +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; + +/** + * The "standard" implementation of Authenticator. + */ +public class BasicAuthenticator extends Authenticator { + /** User roles are recorded in the model like "role:/50", etc. */ + private static final String ROLE_NAMESPACE = "role:/"; + + private static final Log log = LogFactory.getLog(BasicAuthenticator.class); + + private final HttpServletRequest request; + + public BasicAuthenticator(HttpServletRequest request) { + this.request = request; + } + + @Override + public boolean isExistingUser(String username) { + return getUserByUsername(username) != null; + } + + @Override + public User getUserByUsername(String username) { + UserDao userDao = getUserDao(request); + if (userDao == null) { + return null; + } + return userDao.getUserByUsername(username); + } + + @Override + public boolean isCurrentPassword(String username, String clearTextPassword) { + User user = getUserDao(request).getUserByUsername(username); + if (user == null) { + log.trace("Checking password '" + clearTextPassword + + "' for user '" + username + "', but user doesn't exist."); + return false; + } + + String md5NewPassword = Authenticate + .applyMd5Encoding(clearTextPassword); + return md5NewPassword.equals(user.getMd5password()); + } + + @Override + public void recordNewPassword(User user, String newClearTextPassword) { + user.setOldPassword(user.getMd5password()); + user.setMd5password(Authenticate.applyMd5Encoding(newClearTextPassword)); + getUserDao(request).updateUser(user); + } + + @Override + public void recordSuccessfulLogin(User user) { + user.setLoginCount(user.getLoginCount() + 1); + if (user.getFirstTime() == null) { // first login + user.setFirstTime(new Date()); + } + getUserDao(request).updateUser(user); + } + + @Override + public void setLoggedIn(User user) { + HttpSession session = request.getSession(); + createLoginFormBean(user, session); + createLoginStatusBean(user, session); + setSessionTimeoutLimit(session); + recordInUserSessionMap(user, session); + notifyOtherUsers(user, session); + } + + /** + * Put the login bean into the session. + * + * TODO The LoginFormBean is being phased out. + */ + private void createLoginFormBean(User user, HttpSession 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); + } + + /** + * Put the login bean into the session. + * + * TODO this should eventually replace the LoginFormBean. + */ + private void createLoginStatusBean(User user, HttpSession session) { + LoginStatusBean lsb = new LoginStatusBean(user.getURI(), + user.getUsername(), parseUserSecurityLevel(user)); + LoginStatusBean.setBean(session, lsb); + log.info("Adding status bean: " + lsb); + } + + /** + * Editors and other privileged users get a longer timeout interval. + */ + private void setSessionTimeoutLimit(HttpSession session) { + if (LoginStatusBean.getBean(session).isLoggedInAtLeast( + LoginStatusBean.EDITOR)) { + session.setMaxInactiveInterval(PRIVILEGED_TIMEOUT_INTERVAL); + } else { + session.setMaxInactiveInterval(LOGGED_IN_TIMEOUT_INTERVAL); + } + } + + /** + * Record the login in the user/session map. + * + * TODO What is this map used for? + */ + private void recordInUserSessionMap(User user, HttpSession session) { + Map userURISessionMap = Authenticate + .getUserURISessionMapFromContext(session.getServletContext()); + userURISessionMap.put(user.getURI(), session); + } + + /** + * Anyone listening to themodel might need to know that another user is + * logged in. + */ + private void notifyOtherUsers(User user, HttpSession session) { + Authenticate.sendLoginNotifyEvent(new LoginEvent(user.getURI()), + session.getServletContext(), session); + } + + @Override + public List asWhomMayThisUserEdit(User user) { + if (user == null) { + return Collections.emptyList(); + } + + UserDao userDao = getUserDao(request); + if (userDao == null) { + return Collections.emptyList(); + } + + String userUri = user.getURI(); + if (userUri == null) { + return Collections.emptyList(); + } + + return userDao.getIndividualsUserMayEditAs(userUri); + } + + /** + * 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; + } + + /** + * Parse the role URI from User. Don't crash if it is not valid. + */ + private int parseUserSecurityLevel(User user) { + String roleURI = user.getRoleURI(); + try { + if (roleURI.startsWith(ROLE_NAMESPACE)) { + String roleLevel = roleURI.substring(ROLE_NAMESPACE.length()); + return Integer.parseInt(roleLevel); + } else { + return Integer.parseInt(roleURI); + } + } catch (NumberFormatException e) { + log.warn("Invalid RoleURI '" + roleURI + "' for user '" + + user.getURI() + "'"); + return 1; + } + } + +} 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 1d4d85f83..72f676197 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 @@ -7,7 +7,6 @@ import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -24,31 +23,19 @@ import org.apache.commons.logging.LogFactory; import com.hp.hpl.jena.ontology.OntModel; -import edu.cornell.mannlib.vedit.beans.LoginFormBean; import edu.cornell.mannlib.vedit.beans.LoginStatusBean; 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.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator; 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 FreemarkerHttpServlet { - /** - * Maximum inactive interval for a ordinary logged in user session, in - * seconds. - */ - public static final int LOGGED_IN_TIMEOUT_INTERVAL = 300; - - /** Maximum inactive interval for a editor (or better) session, in seconds. */ - public static final int PRIVILEGED_TIMEOUT_INTERVAL = 32000; - private static final Log log = LogFactory.getLog(Authenticate.class .getName()); @@ -155,7 +142,7 @@ public class Authenticate extends FreemarkerHttpServlet { bean.setUsername(username); } - User user = getUserDao(request).getUserByUsername(username); + User user = getAuthenticator(request).getUserByUsername(username); log.trace("User is " + (user == null ? "null" : user.getURI())); if (user == null) { @@ -168,11 +155,7 @@ public class Authenticate extends FreemarkerHttpServlet { return null; } - String md5Password = applyMd5Encoding(password); - - if (!md5Password.equals(user.getMd5password())) { - log.trace("Encoded passwords don't match: right=" - + user.getMd5password() + ", wrong=" + md5Password); + if (!getAuthenticator(request).isCurrentPassword(username, password)) { bean.setMessage(Message.INCORRECT_PASSWORD); return null; } @@ -239,24 +222,15 @@ public class Authenticate extends FreemarkerHttpServlet { 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())) { + String username = bean.getUsername(); + + if (getAuthenticator(request).isCurrentPassword(username, newPassword)) { bean.setMessage(Message.USING_OLD_PASSWORD); return null; } + User user = getAuthenticator(request).getUserByUsername(username); + log.trace("User is " + (user == null ? "null" : user.getURI())); return user; } @@ -266,10 +240,7 @@ public class Authenticate extends FreemarkerHttpServlet { 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); - getUserDao(request).updateUser(user); + getAuthenticator(request).recordNewPassword(user, newPassword); log.debug("Completed first-time password change."); recordLoginInfo(request, user.getUsername()); @@ -282,52 +253,16 @@ public class Authenticate extends FreemarkerHttpServlet { private void recordLoginInfo(HttpServletRequest request, String username) { log.debug("Completed login."); - // Get a fresh user object, so we know it's not stale. - User user = getUserDao(request).getUserByUsername(username); + // Record the login on the user record (start with a fresh copy). + User user = getAuthenticator(request).getUserByUsername(username); + getAuthenticator(request).recordSuccessfulLogin(user); - HttpSession session = request.getSession(); - - // Put the login info into the session. - // TODO the LoginFormBean is being phased out. - 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); - // TODO this should eventually replace the LoginFormBean. - LoginStatusBean lsb = new LoginStatusBean(user.getURI(), - user.getUsername(), parseUserSecurityLevel(user)); - LoginStatusBean.setBean(session, lsb); - log.info("Adding status bean: " + lsb); + // Record that a new user has logged in to this session. + getAuthenticator(request).setLoggedIn(user); // Remove the login process info from the session. + HttpSession session = request.getSession(); 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. - if (lsb.isLoggedInAtLeast(LoginStatusBean.EDITOR)) { - session.setMaxInactiveInterval(PRIVILEGED_TIMEOUT_INTERVAL); - } else { - session.setMaxInactiveInterval(LOGGED_IN_TIMEOUT_INTERVAL); - } - - // 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); - } /** @@ -395,23 +330,17 @@ public class Authenticate extends FreemarkerHttpServlet { // If the user is a self-editor, send them to their home page. User user = getLoggedInUser(request); - if (user != null - && user.getRoleURI() != null - && user.getRoleURI().equals( - Integer.toString(AuthRole.USER.level()))) { - UserDao userDao = getUserDao(request); - if (userDao != null) { - List uris = userDao.getIndividualsUserMayEditAs(user - .getURI()); - if (uris != null && uris.size() > 0) { - String userHomePage = request.getContextPath() - + "/individual?uri=" - + URLEncoder.encode(uris.get(0), "UTF-8"); - log.debug("User is logged in. Redirect as self-editor to " - + userHomePage); - response.sendRedirect(userHomePage); - return; - } + if (userIsANonEditor(user)) { + List uris = getAuthenticator(request).asWhomMayThisUserEdit( + user); + if (uris != null && uris.size() > 0) { + String userHomePage = request.getContextPath() + + "/individual?uri=" + + URLEncoder.encode(uris.get(0), "UTF-8"); + log.debug("User is logged in. Redirect as self-editor to " + + userHomePage); + response.sendRedirect(userHomePage); + return; } } @@ -420,6 +349,15 @@ public class Authenticate extends FreemarkerHttpServlet { response.sendRedirect(getSiteAdminUrl(request)); } + /** Is the logged in user an AuthRole.USER? */ + private boolean userIsANonEditor(User user) { + if (user == null) { + return false; + } + String nonEditorRoleUri = Integer.toString(AuthRole.USER.level()); + return nonEditorRoleUri.equals(user.getRoleURI()); + } + /** * There has been an unexpected exception. Complain mightily. */ @@ -452,43 +390,18 @@ public class Authenticate extends FreemarkerHttpServlet { * What user are we logged in as? */ private User getLoggedInUser(HttpServletRequest request) { - UserDao userDao = getUserDao(request); - if (userDao == null) { - return null; - } - LoginStatusBean lsb = LoginStatusBean.getBean(request); if (!lsb.isLoggedIn()) { log.debug("getLoggedInUser: not logged in"); return null; } - return userDao.getUserByUsername(lsb.getUsername()); + return getAuthenticator(request).getUserByUsername(lsb.getUsername()); } - /** - * 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; + /** Get a reference to the Authenticator. */ + private Authenticator getAuthenticator(HttpServletRequest request) { + return Authenticator.getInstance(request); } /** What's the URL for the login screen? */ @@ -515,19 +428,6 @@ public class Authenticate extends FreemarkerHttpServlet { return LoginProcessBean.getBeanFromSession(request); } - /** - * Parse the role URI from User. Don't crash if it is not valid. - */ - private int parseUserSecurityLevel(User user) { - try { - return Integer.parseInt(user.getRoleURI()); - } catch (NumberFormatException e) { - log.warn("Invalid RoleURI '" + user.getRoleURI() + "' for user '" - + user.getURI() + "'"); - return 1; - } - } - // ---------------------------------------------------------------------- // Public utility methods. // ---------------------------------------------------------------------- diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/edit/AuthenticateTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/edit/AuthenticateTest.java index 1158ecee0..d13a287c3 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/edit/AuthenticateTest.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/edit/AuthenticateTest.java @@ -11,6 +11,7 @@ import static org.junit.Assert.assertNull; import java.net.MalformedURLException; import java.net.URL; import java.util.Collections; +import java.util.Date; import javax.servlet.ServletException; @@ -40,6 +41,7 @@ public class AuthenticateTest extends AbstractTestClass { private static final String USER_OLDHAND_NAME = "oldHandName"; private static final String USER_OLDHAND_URI = "oldHandURI"; private static final String USER_OLDHAND_PASSWORD = "oldHandPassword"; + private static final int USER_OLDHAND_LOGIN_COUNT = 100; private static final String URL_LOGIN_PAGE = Controllers.LOGIN + "?login=block"; @@ -73,6 +75,8 @@ public class AuthenticateTest extends AbstractTestClass { dbaUser.setURI(USER_DBA_URI); dbaUser.setRoleURI("50"); dbaUser.setMd5password(Authenticate.applyMd5Encoding(USER_DBA_PASSWORD)); + dbaUser.setFirstTime(null); + dbaUser.setLoginCount(0); User ohUser = new User(); ohUser.setUsername(USER_OLDHAND_NAME); @@ -80,7 +84,8 @@ public class AuthenticateTest extends AbstractTestClass { ohUser.setRoleURI("1"); ohUser.setMd5password(Authenticate .applyMd5Encoding(USER_OLDHAND_PASSWORD)); - ohUser.setLoginCount(100); + ohUser.setLoginCount(USER_OLDHAND_LOGIN_COUNT); + ohUser.setFirstTime(new Date(0)); userDao = new UserDaoStub(); userDao.addUser(dbaUser); @@ -118,6 +123,7 @@ public class AuthenticateTest extends AbstractTestClass { assertExpectedRedirect(URL_LOGIN_PAGE); assertNoProcessBean(); assertExpectedStatusBean(LOGIN_STATUS_DBA); + assertExpectedUserValues(USER_DBA_NAME, USER_DBA_PASSWORD, 0, false); } @Test @@ -198,6 +204,8 @@ public class AuthenticateTest extends AbstractTestClass { assertExpectedRedirect(URL_LOGIN_PAGE); assertExpectedStatusBean(LOGIN_STATUS_OLDHAND); assertNoProcessBean(); + assertExpectedUserValues(USER_OLDHAND_NAME, USER_OLDHAND_PASSWORD, + USER_OLDHAND_LOGIN_COUNT + 1, true); } // ---------------------------------------------------------------------- @@ -214,6 +222,7 @@ public class AuthenticateTest extends AbstractTestClass { assertExpectedRedirect(URL_LOGIN_PAGE); assertNoStatusBean(); assertExpectedProcessBean(FORCED_PASSWORD_CHANGE, USER_DBA_NAME, "", ""); + assertExpectedUserValues(USER_DBA_NAME, USER_DBA_PASSWORD, 0, false); } @Test @@ -226,6 +235,7 @@ public class AuthenticateTest extends AbstractTestClass { assertExpectedRedirect(URL_HOME_PAGE); assertNoStatusBean(); assertNoProcessBean(); + assertExpectedUserValues(USER_DBA_NAME, USER_DBA_PASSWORD, 0, false); } @Test @@ -239,6 +249,7 @@ public class AuthenticateTest extends AbstractTestClass { assertNoStatusBean(); assertExpectedProcessBean(FORCED_PASSWORD_CHANGE, USER_DBA_NAME, "", "Please enter a password between 6 and 12 characters in length."); + assertExpectedUserValues(USER_DBA_NAME, USER_DBA_PASSWORD, 0, false); } @Test @@ -252,6 +263,7 @@ public class AuthenticateTest extends AbstractTestClass { assertNoStatusBean(); assertExpectedProcessBean(FORCED_PASSWORD_CHANGE, USER_DBA_NAME, "", "The passwords entered do not match."); + assertExpectedUserValues(USER_DBA_NAME, USER_DBA_PASSWORD, 0, false); } @Test @@ -266,6 +278,7 @@ public class AuthenticateTest extends AbstractTestClass { assertExpectedProcessBean(FORCED_PASSWORD_CHANGE, USER_DBA_NAME, "", "Please choose a different password from the " + "temporary one provided initially."); + assertExpectedUserValues(USER_DBA_NAME, USER_DBA_PASSWORD, 0, false); } @Test @@ -278,6 +291,7 @@ public class AuthenticateTest extends AbstractTestClass { assertExpectedRedirect(URL_LOGIN_PAGE); assertExpectedStatusBean(LOGIN_STATUS_DBA); assertNoProcessBean(); + assertExpectedUserValues(USER_DBA_NAME, "NewPassword", 1, true); } // ---------------------------------------------------------------------- @@ -388,6 +402,18 @@ public class AuthenticateTest extends AbstractTestClass { bean.getSecurityLevel()); } + /** Check that this user looks like we expected. */ + private void assertExpectedUserValues(String username, String password, + int loginCount, boolean firstTimeIsSet) { + User user = userDao.getUserByUsername(username); + assertEquals("user " + username + " password", + Authenticate.applyMd5Encoding(password), user.getMd5password()); + assertEquals("user " + username + " login count", loginCount, + user.getLoginCount()); + assertEquals("user " + username + " firstTimeIsSet", firstTimeIsSet, + user.getFirstTime() != null); + } + /** Boilerplate login process for the rediret tests. */ private void loginNotFirstTime() { setProcessBean(LOGGING_IN); @@ -397,6 +423,8 @@ public class AuthenticateTest extends AbstractTestClass { assertExpectedStatusBean(LOGIN_STATUS_OLDHAND); assertNoProcessBean(); + assertExpectedUserValues(USER_OLDHAND_NAME, USER_OLDHAND_PASSWORD, + USER_OLDHAND_LOGIN_COUNT + 1, true); } @SuppressWarnings("unused")