diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginExternalAuthReturn.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginExternalAuthReturn.java index 17287384d..085005edd 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginExternalAuthReturn.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginExternalAuthReturn.java @@ -15,7 +15,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vedit.beans.LoginStatusBean.AuthenticationSource; -import edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean; /** * Handle the return from the external authorization login server. If we are @@ -74,7 +73,6 @@ public class LoginExternalAuthReturn extends BaseLoginServlet { } private void removeLoginProcessArtifacts(HttpServletRequest req) { - LoginProcessBean.removeBean(req); req.getSession().removeAttribute(ATTRIBUTE_REFERRER); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginRedirector.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginRedirector.java index 6f0ee3cf9..3cb8116c1 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginRedirector.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginRedirector.java @@ -17,6 +17,7 @@ import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vedit.beans.LoginStatusBean; import edu.cornell.mannlib.vitro.webapp.beans.DisplayMessage; import edu.cornell.mannlib.vitro.webapp.controller.Controllers; +import edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean; /** * A user has just completed the login process. What page do we direct them to? @@ -24,14 +25,13 @@ import edu.cornell.mannlib.vitro.webapp.controller.Controllers; public class LoginRedirector { private static final Log log = LogFactory.getLog(LoginRedirector.class); - private static final String ATTRIBUTE_RETURN_FROM_FORCED_LOGIN = "return_from_forced_login"; - private final HttpServletRequest request; private final HttpServletResponse response; private final HttpSession session; - private final String urlOfRestrictedPage; private final String uriOfAssociatedIndividual; + private final String loginProcessPage; + private final String afterLoginPage; public LoginRedirector(HttpServletRequest request, HttpServletResponse response) { @@ -39,18 +39,12 @@ public class LoginRedirector { this.session = request.getSession(); this.response = response; - urlOfRestrictedPage = getUrlOfRestrictedPage(); uriOfAssociatedIndividual = getAssociatedIndividualUri(); - } - - /** Were we forced to log in when trying to access a restricted page? */ - private String getUrlOfRestrictedPage() { - String url = (String) session - .getAttribute(ATTRIBUTE_RETURN_FROM_FORCED_LOGIN); - session.removeAttribute(ATTRIBUTE_RETURN_FROM_FORCED_LOGIN); - log.debug("URL of restricted page is " + url); - return url; + LoginProcessBean processBean = LoginProcessBean.getBean(request); + log.debug("process bean is: " + processBean); + loginProcessPage = processBean.getLoginPageUrl(); + afterLoginPage = processBean.getAfterLoginUrl(); } /** Is there an Individual associated with this user? */ @@ -76,30 +70,79 @@ public class LoginRedirector { } public void redirectLoggedInUser() throws IOException { - if (isForcedFromRestrictedPage()) { - log.debug("Returning to restricted page."); - response.sendRedirect(urlOfRestrictedPage); - } else if (isUserEditorOrBetter()) { - log.debug("Going to site admin page."); - response.sendRedirect(getSiteAdminPageUrl()); - } else if (isSelfEditorWithIndividual()) { - log.debug("Going to Individual home page."); - response.sendRedirect(getAssociatedIndividualHomePage()); - } else { - log.debug("User not recognized. Going to application home."); - DisplayMessage.setMessage(request, "You have logged in, " - + "but the system contains no profile for you."); + try { + if (isSelfEditorWithIndividual()) { + log.debug("Going to Individual home page."); + response.sendRedirect(getAssociatedIndividualHomePage()); + } else if (isMerelySelfEditor()) { + log.debug("User not recognized. Going to application home."); + DisplayMessage.setMessage(request, "You have logged in, " + + "but the system contains no profile for you."); + response.sendRedirect(getApplicationHomePageUrl()); + } else { + if (hasSomeplaceToGoAfterLogin()) { + log.debug("Returning to requested page: " + afterLoginPage); + response.sendRedirect(afterLoginPage); + } else if (loginProcessPage == null) { + log.debug("Don't know what to do. Go home."); + response.sendRedirect(getApplicationHomePageUrl()); + } else if (isLoginPage(loginProcessPage)) { + log.debug("Coming from /login. Going to site admin page."); + response.sendRedirect(getSiteAdminPageUrl()); + } else { + log.debug("Coming from a login widget. Going back there."); + response.sendRedirect(loginProcessPage); + } + } + LoginProcessBean.removeBean(request); + } catch (IOException e) { + log.debug("Problem with re-direction", e); response.sendRedirect(getApplicationHomePageUrl()); } } - private boolean isForcedFromRestrictedPage() { - return urlOfRestrictedPage != null; + public void redirectCancellingUser() throws IOException { + try { + if (hasSomeplaceToGoAfterLogin()) { + log.debug("Returning to requested page: " + afterLoginPage); + response.sendRedirect(afterLoginPage); + } else if (loginProcessPage == null) { + log.debug("Don't know what to do. Go home."); + response.sendRedirect(getApplicationHomePageUrl()); + } else if (isLoginPage(loginProcessPage)) { + log.debug("Coming from /login. Going to home."); + response.sendRedirect(getApplicationHomePageUrl()); + } else { + log.debug("Coming from a login widget. Going back there."); + response.sendRedirect(loginProcessPage); + } + LoginProcessBean.removeBean(request); + } catch (IOException e) { + log.debug("Problem with re-direction", e); + response.sendRedirect(getApplicationHomePageUrl()); + } } - private boolean isUserEditorOrBetter() { - return LoginStatusBean.getBean(session).isLoggedInAtLeast( - LoginStatusBean.EDITOR); + public void redirectUnrecognizedExternalUser(String username) + throws IOException { + log.debug("Redirecting unrecognized external user: " + username); + DisplayMessage.setMessage(request, + "VIVO cannot find a profile for your account."); + response.sendRedirect(getApplicationHomePageUrl()); + } + + private boolean hasSomeplaceToGoAfterLogin() { + return afterLoginPage != null; + } + + private boolean isMerelySelfEditor() { + return LoginStatusBean.getBean(session).isLoggedInExactly( + LoginStatusBean.NON_EDITOR); + } + + private boolean isLoginPage(String page) { + return ((page != null) && page.endsWith(request.getContextPath() + + Controllers.LOGIN)); } private String getSiteAdminPageUrl() { @@ -120,14 +163,6 @@ public class LoginRedirector { } } - public void redirectUnrecognizedExternalUser(String username) - throws IOException { - log.debug("Redirecting unrecognized external user: " + username); - DisplayMessage.setMessage(request, - "VIVO cannot find a profile for your account."); - response.sendRedirect(getApplicationHomePageUrl()); - } - /** * The application home page can be overridden by an attribute in the * ServletContext. Further, it can either be an absolute URL, or it can be @@ -145,14 +180,4 @@ public class LoginRedirector { } return request.getContextPath(); } - - // ---------------------------------------------------------------------- - // static helper methods - // ---------------------------------------------------------------------- - - public static void setReturnUrlFromForcedLogin(HttpServletRequest request, - String url) { - request.getSession().setAttribute(ATTRIBUTE_RETURN_FROM_FORCED_LOGIN, - url); - } } 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 c1b112990..c370360a7 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 @@ -8,6 +8,8 @@ import static edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean import static edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean.State.NOWHERE; import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.HashMap; @@ -28,6 +30,7 @@ import com.hp.hpl.jena.ontology.OntModel; import edu.cornell.mannlib.vedit.beans.LoginStatusBean; import edu.cornell.mannlib.vedit.beans.LoginStatusBean.AuthenticationSource; 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.authenticate.Authenticator; @@ -41,6 +44,24 @@ public class Authenticate extends VitroHttpServlet { private static final Log log = LogFactory.getLog(Authenticate.class .getName()); + /** + * If this is set at any point in the process, store it as the post-login + * destination. + * + * NOTE: we expect URL-encoding on this parameter, and will decode it when + * we read it. + */ + private static final String PARAMETER_AFTER_LOGIN = "afterLogin"; + + /** + * If this is set at any point in the process, store the referrer as the + * post-login destination. + */ + private static final String PARAMETER_RETURN = "return"; + + /** If this is set, a status of NOWHERE should be treated as LOGGING_IN. */ + private static final String PARAMETER_LOGGING_IN = "loginForm"; + /** The username field on the login form. */ private static final String PARAMETER_USERNAME = "loginName"; @@ -68,6 +89,8 @@ public class Authenticate extends VitroHttpServlet { VitroRequest vreq = new VitroRequest(request); try { + recordLoginProcessPages(vreq); + // Where do we stand in the process? State entryState = getCurrentLoginState(vreq); dumpStateToLog("entry", entryState, vreq); @@ -95,7 +118,7 @@ public class Authenticate extends VitroHttpServlet { // Send them on their way. switch (exitState) { case NOWHERE: - redirectCancellingUser(vreq, response); + new LoginRedirector(vreq, response).redirectCancellingUser(); break; case LOGGING_IN: showLoginScreen(vreq, response); @@ -113,30 +136,77 @@ public class Authenticate extends VitroHttpServlet { } + /** + * If they supply an after-login page, record it and use the Login page for + * the process. + * + * If they supply a return flag, record the referrer as the after-login page + * and use the Login page for the process. + * + * Otherwise, use the current page for the process. + */ + private void recordLoginProcessPages(HttpServletRequest request) { + LoginProcessBean bean = LoginProcessBean.getBean(request); + + String afterLoginUrl = request.getParameter(PARAMETER_AFTER_LOGIN); + if (afterLoginUrl != null) { + try { + String decoded = URLDecoder.decode(afterLoginUrl, "UTF-8"); + bean.setAfterLoginUrl(decoded); + } catch (UnsupportedEncodingException e) { + log.error("Really? No UTF-8 encoding?"); + } + } + + String returnParameter = request.getParameter(PARAMETER_RETURN); + if (returnParameter != null) { + String referrer = request.getHeader("referer"); + bean.setAfterLoginUrl(referrer); + } + + if (bean.getAfterLoginUrl() != null) { + bean.setLoginPageUrl(request.getContextPath() + Controllers.LOGIN); + } else { + bean.setLoginPageUrl(request.getHeader("referer")); + } + } + /** * Where are we in the process? Logged in? Not? Somewhere in between? */ private State getCurrentLoginState(HttpServletRequest request) { + State currentState; + HttpSession session = request.getSession(false); if (session == null) { + currentState = NOWHERE; log.debug("no session: current state is NOWHERE"); - return NOWHERE; - } - - if (LoginStatusBean.getBean(request).isLoggedIn()) { + } else if (LoginStatusBean.getBean(request).isLoggedIn()) { + currentState = LOGGED_IN; log.debug("found a LoginStatusBean: current state is LOGGED IN"); - return LOGGED_IN; - } - - if (LoginProcessBean.isBean(request)) { - State state = LoginProcessBean.getBean(request).getState(); - log.debug("state from LoginProcessBean is " + state); - return state; + } else if (LoginProcessBean.isBean(request)) { + currentState = LoginProcessBean.getBean(request).getState(); + log.debug("state from LoginProcessBean is " + currentState); } else { + currentState = NOWHERE; log.debug("no LoginSessionBean, no LoginProcessBean: " + "current state is NOWHERE"); - return NOWHERE; } + + if ((currentState == NOWHERE) && isLoggingInByParameter(request)) { + currentState = LOGGING_IN; + log.debug("forced from NOWHERE to LOGGING_IN by '" + + PARAMETER_LOGGING_IN + "' parameter"); + } + + return currentState; + } + + /** + * If this parameter is present, we aren't NOWHERE. + */ + private boolean isLoggingInByParameter(HttpServletRequest request) { + return (request.getParameter(PARAMETER_LOGGING_IN) != null); } /** @@ -288,7 +358,6 @@ public class Authenticate extends VitroHttpServlet { log.debug("Completed login: " + username); getAuthenticator(request).recordLoginAgainstUserAccount(username, AuthenticationSource.INTERNAL); - LoginProcessBean.removeBean(request); } /** @@ -301,15 +370,14 @@ public class Authenticate extends VitroHttpServlet { getAuthenticator(request).recordNewPassword(username, newPassword); getAuthenticator(request).recordLoginAgainstUserAccount(username, AuthenticationSource.INTERNAL); - LoginProcessBean.removeBean(request); } /** * State change: they decided to cancel the login. */ private void transitionToNowhere(HttpServletRequest request) { + LoginProcessBean.getBean(request).setState(NOWHERE); log.debug("Cancelling login."); - LoginProcessBean.removeBean(request); } /** @@ -331,35 +399,17 @@ public class Authenticate extends VitroHttpServlet { throws IOException { log.debug("logging in."); - String referringPage = vreq.getHeader("referer"); - if (referringPage == null) { - log.warn("No referring page on the request"); - referringPage = getHomeUrl(vreq); - } - response.sendRedirect(referringPage); + String loginProcessPage = LoginProcessBean.getBean(vreq) + .getLoginPageUrl(); + response.sendRedirect(loginProcessPage); return; } - /** - * Exit: user cancelled the login, so show them the home page. - */ - private void redirectCancellingUser(HttpServletRequest request, - HttpServletResponse response) throws IOException { - log.debug("User cancelled the login. Redirect to site admin page."); - LoginProcessBean.removeBean(request); - response.sendRedirect(getHomeUrl(request)); - } - /** Get a reference to the Authenticator. */ private Authenticator getAuthenticator(HttpServletRequest request) { return Authenticator.getInstance(request); } - /** What's the URL for the home page? */ - private String getHomeUrl(HttpServletRequest request) { - return request.getContextPath(); - } - // ---------------------------------------------------------------------- // Public utility methods. // ---------------------------------------------------------------------- @@ -422,7 +472,7 @@ public class Authenticate extends VitroHttpServlet { private void dumpStateToLog(String label, State state, VitroRequest vreq) { log.debug("State on " + label + ": " + state); - + if (log.isTraceEnabled()) { log.trace("Status bean on " + label + ": " + LoginStatusBean.getBean(vreq)); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java index f7f79fd6b..21e87bc0e 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/FreemarkerHttpServlet.java @@ -319,7 +319,7 @@ public class FreemarkerHttpServlet extends VitroHttpServlet { } urls.put("search", urlBuilder.getPortalUrl(Route.SEARCH)); urls.put("termsOfUse", urlBuilder.getPortalUrl(Route.TERMS_OF_USE)); - urls.put("login", urlBuilder.getPortalUrl(Route.LOGIN)); + urls.put("login", urlBuilder.getLoginUrl()); urls.put("logout", urlBuilder.getLogoutUrl()); urls.put("siteAdmin", urlBuilder.getPortalUrl(Route.SITE_ADMIN)); urls.put("siteIcons", urlBuilder.getPortalUrl(themeDir + "/site_icons")); // deprecated diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/UrlBuilder.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/UrlBuilder.java index e685d4fca..6e09fddab 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/UrlBuilder.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/freemarker/UrlBuilder.java @@ -26,6 +26,7 @@ public class UrlBuilder { public enum Route { ABOUT("/about"), + AUTHENTICATE("/authenticate"), BROWSE("/browse"), CONTACT("/contact"), INDIVIDUAL("/individual"), @@ -120,6 +121,10 @@ public class UrlBuilder { return contextPath; } + public String getLoginUrl() { + return getPortalUrl(Route.AUTHENTICATE, "return", "true"); + } + public String getLogoutUrl() { return getPortalUrl(Route.LOGOUT); } 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 index 4c21c830a..09d15fd8b 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/login/LoginProcessBean.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/login/LoginProcessBean.java @@ -164,6 +164,12 @@ public class LoginProcessBean { /** What arguments are needed to format the message? */ private Object[] messageArguments = NO_ARGUMENTS; + /** Where is the interaction taking place? */ + private String loginPageUrl; + + /** Where do we go when finished? */ + private String afterLoginUrl; + /** * 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. @@ -214,12 +220,29 @@ public class LoginProcessBean { this.username = username; } + public String getLoginPageUrl() { + return loginPageUrl; + } + + public void setLoginPageUrl(String loginPageUrl) { + this.loginPageUrl = loginPageUrl; + } + + public String getAfterLoginUrl() { + return afterLoginUrl; + } + + public void setAfterLoginUrl(String afterLoginUrl) { + this.afterLoginUrl = afterLoginUrl; + } + @Override public String toString() { return "LoginProcessBean[state=" + currentState + ", message=" + message + ", messageArguments=" + Arrays.deepToString(messageArguments) + ", username=" - + username + "]"; + + username + ", loginPageUrl=" + loginPageUrl + + ", afterLoginUrl=" + afterLoginUrl + "]"; } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/widgets/LoginWidget.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/widgets/LoginWidget.java index 665cdfa65..18f96d8fc 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/widgets/LoginWidget.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/widgets/LoginWidget.java @@ -106,14 +106,11 @@ public class LoginWidget extends Widget { } /** - * User is just starting the login process. Be sure that we have a - * {@link LoginProcessBean} with the correct status. Show them the login - * screen. + * User is starting the login process. Show them the login screen. */ private WidgetTemplateValues showLoginScreen(HttpServletRequest request) throws IOException { LoginProcessBean bean = LoginProcessBean.getBean(request); - bean.setState(State.LOGGING_IN); log.trace("Going to login screen: " + bean); WidgetTemplateValues values = new WidgetTemplateValues(Macro.LOGIN.toString()); @@ -150,7 +147,6 @@ public class LoginWidget extends Widget { */ private WidgetTemplateValues showPasswordChangeScreen(HttpServletRequest request) { LoginProcessBean bean = LoginProcessBean.getBean(request); - bean.setState(State.FORCED_PASSWORD_CHANGE); log.trace("Going to password change screen: " + bean); WidgetTemplateValues values = new WidgetTemplateValues( 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 2b4049242..ebcbc6323 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 @@ -9,6 +9,7 @@ import static org.junit.Assert.fail; import java.net.URL; import java.util.Arrays; +import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -17,6 +18,9 @@ import java.util.Set; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; import stubs.javax.servlet.ServletConfigStub; import stubs.javax.servlet.ServletContextStub; @@ -27,38 +31,204 @@ import edu.cornell.mannlib.vedit.beans.LoginStatusBean; import edu.cornell.mannlib.vedit.beans.LoginStatusBean.AuthenticationSource; import edu.cornell.mannlib.vitro.testing.AbstractTestClass; import edu.cornell.mannlib.vitro.webapp.beans.User; -import edu.cornell.mannlib.vitro.webapp.controller.Controllers; import edu.cornell.mannlib.vitro.webapp.controller.authenticate.AuthenticatorStub; -import edu.cornell.mannlib.vitro.webapp.controller.authenticate.LoginRedirector; import edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean; import edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean.State; /** - * Test the Authentate class. + *
+ * Test the Authenticate class. + * + * This uses parameterized unit tests. Several sets of test data are set up, and + * then each test is run with each set of data. + * + * Each set of test data includes + * information about the user who is logging in, + * information about how the user began the login process + * information about where the user should end up + * + * We run the tests with these users: + * A DBA who has never logged in before + * A DBA who has logged in before + * A self-editor who has logged in before + * A self-editor wannabe, who has never logged in and has no profile. + * + * We run the tests with the assumption that the user started from: + * The login page + * A page that holds the login widget + * A forced login + * A login link on some page + **/ +@RunWith(value = Parameterized.class) public class AuthenticateTest extends AbstractTestClass { - private static final String USER_DBA_NAME = "dbaName"; - private static final String USER_DBA_URI = "dbaURI"; - private static final String USER_DBA_PASSWORD = "dbaPassword"; - 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; + // ---------------------------------------------------------------------- + // Helper classes + // ---------------------------------------------------------------------- - private static final String URL_LOGIN_PAGE = "http://my.local.site/vivo/" - + Controllers.LOGIN; - private static final String URL_SITE_ADMIN_PAGE = Controllers.SITE_ADMIN; + private static class UserInfo { + final String username; + final String uri; + final String password; + final int securityLevel; + final int loginCount; - private static final String URL_HOME_PAGE = ""; - private static final String URL_SESSION_REDIRECT = "/sessionRedirect"; - private static final String URL_CONTEXT_REDIRECT_LOCAL = "/servletContextRedirect"; - private static final String URL_CONTEXT_REDIRECT_REMOTE = "http://servletContextRedirect"; - private static final String URL_SELF_EDITOR_PAGE = "/individual?uri=selfEditorURI"; + public UserInfo(String username, String uri, String password, + int securityLevel, int loginCount) { + this.username = username; + this.uri = uri; + this.password = password; + this.securityLevel = securityLevel; + this.loginCount = loginCount; + } - private static final LoginStatusBean LOGIN_STATUS_DBA = new LoginStatusBean( - USER_DBA_URI, USER_DBA_NAME, LoginStatusBean.DBA, - AuthenticationSource.INTERNAL); + @Override + public String toString() { + return "UserInfo[username=" + username + ", uri=" + uri + + ", password=" + password + ", securityLevel=" + + securityLevel + ", loginCount=" + loginCount + "]"; + } + } + + private static class HowDidWeGetHere { + final String afterLoginUrl; + final boolean returnParameterSet; + final String referrer; + + public HowDidWeGetHere(String afterLoginUrl, + boolean returnParameterSet, String referrer) { + this.afterLoginUrl = afterLoginUrl; + this.returnParameterSet = returnParameterSet; + this.referrer = referrer; + } + + @Override + public String toString() { + return "HowDidWeGetHere[afterLoginUrl=" + afterLoginUrl + + ", returnParameterSet=" + returnParameterSet + + ", referrer=" + referrer + "]"; + } + } + + private static class WhereTo { + final String expectedContinueUrl; + final String expectedCompletionUrl; + final String expectedCancelUrl; + + public WhereTo(String expectedContinueUrl, + String expectedCompletionUrl, String expectedCancelUrl) { + this.expectedContinueUrl = expectedContinueUrl; + this.expectedCompletionUrl = expectedCompletionUrl; + this.expectedCancelUrl = expectedCancelUrl; + } + + @Override + public String toString() { + return "WhereTo[expectedContinueUrl=" + expectedContinueUrl + + ", expectedCompletionUrl=" + expectedCompletionUrl + + ", expectedCancelUrl=" + expectedCancelUrl + "]"; + } + } + + // ---------------------------------------------------------------------- + // The parameters + // ---------------------------------------------------------------------- + + // --------- Pages ---------- + + /** the login page */ + private static final String URL_LOGIN = "/vivo/login"; + + /** some page with a login widget on it. */ + private static final String URL_WIDGET = "/vivo/widgetPage"; + + /** a restricted page that forces a login. */ + private static final String URL_RESTRICTED = "/vivo/otherPage"; + + /** a page with a login link. */ + private static final String URL_LINK = "/vivo/linkPage"; + + // pages that we might end up on. + private static final String URL_HOME = "/vivo"; + private static final String URL_SITE_ADMIN = "/vivo/siteAdmin"; + private static final String URL_SELF_PROFILE = "/vivo/individual?uri=old_self_associated_uri"; + + // --------- Users ---------- + + /** A DBA who has never logged in (forces password change). */ + private static final UserInfo NEW_DBA = new UserInfo("new_dba_name", + "new_dba_uri", "new_dba_pw", 50, 0); + + /** A DBA who has logged in before. */ + private static final UserInfo OLD_DBA = new UserInfo("old_dba_name", + "old_dba_uri", "old_dba_pw", 50, 5); + + /** A self-editor who has logged in before and has a profile. */ + private static final UserInfo OLD_SELF = new UserInfo("old_self_name", + "old_self_uri", "old_self_pw", 1, 100); + + /** A self-editor who has never logged in and has no profile. */ + private static final UserInfo NEW_STRANGER = new UserInfo( + "new_stranger_name", "new_stranger_uri", "stranger_pw", 1, 0); + + // --------- Starting circumstances ---------- + + private static final HowDidWeGetHere FROM_FORCED = new HowDidWeGetHere( + URL_RESTRICTED, false, URL_RESTRICTED); + + private static final HowDidWeGetHere FROM_LINK = new HowDidWeGetHere(null, + true, URL_LINK); + + private static final HowDidWeGetHere FROM_WIDGET = new HowDidWeGetHere( + null, false, URL_WIDGET); + + private static final HowDidWeGetHere FROM_LOGIN = new HowDidWeGetHere(null, + false, URL_LOGIN); + + // --------- All sets of test data ---------- + + @Parameters + public static Collection