diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsFirstTimeExternalPage.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsFirstTimeExternalPage.java index fd556b155..78ea1c7ec 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsFirstTimeExternalPage.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsFirstTimeExternalPage.java @@ -124,6 +124,11 @@ public class UserAccountsFirstTimeExternalPage extends UserAccountsPage { + "'"; return; } + if (!Authenticator.getInstance(vreq).isUserPermittedToLogin(null)) { + bogusMessage = "User logins are temporarily disabled " + + "while the system is being maintained."; + return; + } } public boolean isBogus() { diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsUserController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsUserController.java index ac1a73519..e2f7a47e6 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsUserController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsUserController.java @@ -13,6 +13,7 @@ import edu.cornell.mannlib.vitro.webapp.beans.DisplayMessage; import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator; +import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator.LoginNotPermitted; import edu.cornell.mannlib.vitro.webapp.controller.authenticate.LoginRedirector; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.RedirectResponseValues; @@ -108,10 +109,15 @@ public class UserAccountsUserController extends FreemarkerHttpServlet { if (page.isBogus()) { return showHomePage(vreq, page.getBogusMessage()); } else if (page.isSubmit() && page.isValid()) { - UserAccount userAccount = page.createAccount(); - Authenticator auth = Authenticator.getInstance(vreq); - auth.recordLoginAgainstUserAccount(userAccount, EXTERNAL); - return showLoginRedirection(vreq, page.getAfterLoginUrl()); + try { + UserAccount userAccount = page.createAccount(); + Authenticator auth = Authenticator.getInstance(vreq); + auth.recordLoginAgainstUserAccount(userAccount, EXTERNAL); + return showLoginRedirection(vreq, page.getAfterLoginUrl()); + } catch (LoginNotPermitted e) { + // This should have been anticipated by the page. + return showHomePage(vreq, BOGUS_STANDARD_MESSAGE); + } } else { return page.showPage(); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AdminLoginController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AdminLoginController.java index 66dc2c3ae..9863a3436 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AdminLoginController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AdminLoginController.java @@ -15,6 +15,7 @@ import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions; import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator.LoginNotPermitted; 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.freemarker.responsevalues.RedirectResponseValues; @@ -44,6 +45,7 @@ public class AdminLoginController extends FreemarkerHttpServlet { private static final String MESSAGE_NO_EMAIL_ADDRESS = "errorNoEmail"; private static final String MESSAGE_NO_PASSWORD = "errorNoPassword"; + private static final String MESSAGE_LOGIN_DISABLED = "errorLoginDisabled"; private static final String MESSAGE_LOGIN_FAILED = "errorLoginFailed"; private static final String MESSAGE_NEW_PASSWORD_REQUIRED = "newPasswordRequired"; private static final String MESSAGE_NEW_PASSWORD_WRONG_LENGTH = "errorNewPasswordWrongLength"; @@ -101,6 +103,9 @@ public class AdminLoginController extends FreemarkerHttpServlet { if (password.isEmpty()) { return showForm(MESSAGE_NO_PASSWORD); } + if (!loginPermitted()) { + return showForm(MESSAGE_LOGIN_DISABLED); + } if (newPasswordRequired()) { if (newPassword.isEmpty()) { return showForm(MESSAGE_NEW_PASSWORD_REQUIRED); @@ -127,6 +132,10 @@ public class AdminLoginController extends FreemarkerHttpServlet { return showForm(MESSAGE_LOGIN_FAILED); } + private boolean loginPermitted() { + return auth.isUserPermittedToLogin(userAccount); + } + private boolean newPasswordRequired() { return auth.isCurrentPassword(userAccount, password) && (userAccount.isPasswordChangeRequired()); @@ -138,17 +147,21 @@ public class AdminLoginController extends FreemarkerHttpServlet { } private boolean tryToLogin() { - if (auth.isCurrentPassword(userAccount, password)) { - auth.recordLoginAgainstUserAccount(userAccount, INTERNAL); - - if (!newPassword.isEmpty()) { - auth.recordNewPassword(userAccount, newPassword); - } - - return true; - } else { + if (!auth.isCurrentPassword(userAccount, password)) { return false; } + + try { + auth.recordLoginAgainstUserAccount(userAccount, INTERNAL); + } catch (LoginNotPermitted e) { + return false; + } + + if (!newPassword.isEmpty()) { + auth.recordNewPassword(userAccount, newPassword); + } + + return true; } private ResponseValues showForm(String... codes) { 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 index fb86eb1d1..6cb4b49cf 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/Authenticator.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/Authenticator.java @@ -23,6 +23,14 @@ import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; * This needs to be based on a HttpSession, because things like the UserDAO are * tied to the session. It seemed easier to base it on a HttpServletRequest, * which we can use to get the session. + * + * TODO: Wouldn't it be cool if we could remove the LoginNotPermitted exception? + * Perhaps we could have a sub-object called an Authenticator.ForUser, and you + * call a getAuthenticatorForUser() method which returns null if your login has + * been disabled. Then, that object would provide these methods: + * accountRequiresEditing(), getAssociatedIndividualUris(), isCurrentPassword(), + * recordLoginAgainstUserAccount(), recordNewPassword(). If you didn't have such + * an object, you couldn't even call these methods. */ public abstract class Authenticator { // ---------------------------------------------------------------------- @@ -48,11 +56,11 @@ public abstract class Authenticator { public static Authenticator getInstance(HttpServletRequest request) { ServletContext ctx = request.getSession().getServletContext(); Object attribute = ctx.getAttribute(FACTORY_ATTRIBUTE_NAME); - if (! (attribute instanceof AuthenticatorFactory)) { + if (!(attribute instanceof AuthenticatorFactory)) { attribute = new BasicAuthenticator.Factory(); ctx.setAttribute(FACTORY_ATTRIBUTE_NAME, attribute); } - AuthenticatorFactory factory = (AuthenticatorFactory) attribute; + AuthenticatorFactory factory = (AuthenticatorFactory) attribute; return factory.getInstance(request); } @@ -77,6 +85,16 @@ public abstract class Authenticator { */ public abstract UserAccount getAccountForInternalAuth(String emailAddress); + /** + * Is this user permitted to login? Some Authenticators might disable logins + * for certain users. + * + * Behavior when userAccount is null depends on the particular + * Authenticator. An answer of "true" presumably means that the user will be + * permitted to login and create an account on the fly. + */ + public abstract boolean isUserPermittedToLogin(UserAccount userAccount); + /** * Internal: does this UserAccount have this password? False if the * userAccount is null. @@ -113,9 +131,14 @@ public abstract class Authenticator { * - record the user in the session map * - notify other users of the model * + * + * @throws LoginNotPermitted + * if the Authenticator denies this user the ability to login. + * This should be thrown if and only if isUserPermittedToLogin() + * returns false. */ public abstract void recordLoginAgainstUserAccount(UserAccount userAccount, - AuthenticationSource authSource); + AuthenticationSource authSource) throws LoginNotPermitted; /** *
@@ -173,4 +196,12 @@ public abstract class Authenticator { return false; } } + + // ---------------------------------------------------------------------- + // Exceptions + // ---------------------------------------------------------------------- + + public static class LoginNotPermitted extends Exception { + // no other information + } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/BaseLoginServlet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/BaseLoginServlet.java index 22698eda5..20bcd402e 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/BaseLoginServlet.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/BaseLoginServlet.java @@ -24,6 +24,11 @@ public class BaseLoginServlet extends HttpServlet { protected static final Message MESSAGE_LOGIN_FAILED = new LoginProcessBean.Message( "External login failed.", LoginProcessBean.MLevel.ERROR); + /** Tell the user that it's nothing personal, they just aren't allowed in. */ + protected static final Message MESSAGE_LOGIN_DISABLED = new LoginProcessBean.Message( + "User logins are temporarily disabled while the system is being maintained.", + LoginProcessBean.MLevel.ERROR); + protected Authenticator getAuthenticator(HttpServletRequest req) { return Authenticator.getInstance(req); } 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 index 347d6dc86..918630107 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/BasicAuthenticator.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/BasicAuthenticator.java @@ -76,6 +76,13 @@ public class BasicAuthenticator extends Authenticator { return userAccountsDao.getUserAccountByExternalAuthId(externalAuthId); } + @Override + public boolean isUserPermittedToLogin(UserAccount userAccount) { + // All users are permitted to login. If the user doesn't have an account + // yet (userAccount is null), an account should be created for them. + return true; + } + @Override public boolean isCurrentPassword(UserAccount userAccount, String clearTextPassword) { 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 e8dfd4cea..216bb12cd 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 @@ -17,6 +17,7 @@ import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vedit.beans.LoginStatusBean.AuthenticationSource; import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; import edu.cornell.mannlib.vitro.webapp.controller.accounts.user.UserAccountsFirstTimeExternalPage; +import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator.LoginNotPermitted; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean; @@ -77,6 +78,14 @@ public class LoginExternalAuthReturn extends BaseLoginServlet { UserAccount userAccount = getAuthenticator(req) .getAccountForExternalAuth(externalAuthId); + + if (!getAuthenticator(req).isUserPermittedToLogin(userAccount)) { + log.debug("Logins disabled for " + userAccount); + complainAndReturnToReferrer(req, resp, ATTRIBUTE_REFERRER, + MESSAGE_LOGIN_DISABLED); + return; + } + if (userAccount == null) { log.debug("Creating new account for " + externalAuthId + ", return to '" + afterLoginUrl + "'"); @@ -84,12 +93,20 @@ public class LoginExternalAuthReturn extends BaseLoginServlet { externalAuthId, afterLoginUrl); resp.sendRedirect(UrlBuilder.getUrl("/accounts/firstTimeExternal")); return; - } else { + } + + try { log.debug("Logging in as " + userAccount.getUri()); getAuthenticator(req).recordLoginAgainstUserAccount(userAccount, AuthenticationSource.EXTERNAL); new LoginRedirector(req, afterLoginUrl).redirectLoggedInUser(resp); return; + } catch (LoginNotPermitted e) { + // should have been caught by isUserPermittedToLogin() + log.debug("Logins disabled for " + userAccount); + complainAndReturnToReferrer(req, resp, ATTRIBUTE_REFERRER, + MESSAGE_LOGIN_DISABLED); + return; } } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/ProgramLogin.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/ProgramLogin.java index bdaef9162..ab3c05577 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/ProgramLogin.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/ProgramLogin.java @@ -18,6 +18,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; +import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator.LoginNotPermitted; /** * Provide a means for programmatic login If they provide the right parameters, @@ -29,13 +30,18 @@ public class ProgramLogin extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - new ProgramLoginCore(req, resp).process(); + try { + new ProgramLoginCore(req, resp).process(); + } catch (LoginNotPermitted e) { + // This should have been prevented by the test for loginDisabled() + throw new ServletException(e); + } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - new ProgramLoginCore(req, resp).process(); + doGet(req, resp); } static class ProgramLoginCore { @@ -50,6 +56,8 @@ public class ProgramLogin extends HttpServlet { + " parameter is required."; private static final String MESSAGE_WRONG_USER_OR_PASSWORD = PARAM_EMAIL_ADDRESS + " or " + PARAM_PASSWORD + " is incorrect."; + private static final String MESSAGE_LOGIN_DISABLED = "User logins are " + + "temporarily disabled while the system is being maintained."; private static final String MESSAGE_NEED_NEW_PASSWORD = "first-time login: " + PARAM_NEW_PASSWORD + " parameter is required."; private static final String MESSAGE_NEW_PASSWORD_NOT_NEEDED = "not first-time login: " @@ -90,7 +98,7 @@ public class ProgramLogin extends HttpServlet { .getAccountForInternalAuth(this.emailAddress); } - void process() throws IOException { + void process() throws IOException, LoginNotPermitted { if (emailAddress.isEmpty()) { sendError(MESSAGE_NEED_EMAIL_ADDRESS); return; @@ -104,6 +112,11 @@ public class ProgramLogin extends HttpServlet { return; } + if (loginDisabled()) { + sendError(MESSAGE_LOGIN_DISABLED); + return; + } + if (!isPasswordChangeRequired()) { if (!newPassword.isEmpty()) { sendError(MESSAGE_NEW_PASSWORD_NOT_NEEDED); @@ -147,6 +160,10 @@ public class ProgramLogin extends HttpServlet { return auth.isCurrentPassword(userAccount, password); } + private boolean loginDisabled() { + return !auth.isUserPermittedToLogin(userAccount); + } + private boolean newPasswordIsValidPasswordLength() { return (newPassword.length() >= MIN_PASSWORD_LENGTH) && (newPassword.length() <= MAX_PASSWORD_LENGTH); @@ -160,11 +177,11 @@ public class ProgramLogin extends HttpServlet { return (userAccount.isPasswordChangeRequired()); } - private void recordLogin() { + private void recordLogin() throws LoginNotPermitted { auth.recordLoginAgainstUserAccount(userAccount, INTERNAL); } - private void recordLoginWithPasswordChange() { + private void recordLoginWithPasswordChange() throws LoginNotPermitted { auth.recordNewPassword(userAccount, newPassword); auth.recordLoginAgainstUserAccount(userAccount, INTERNAL); } 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 1949009e6..df1e5bbca 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 @@ -33,6 +33,7 @@ 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; +import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator.LoginNotPermitted; import edu.cornell.mannlib.vitro.webapp.controller.authenticate.LoginInProcessFlag; import edu.cornell.mannlib.vitro.webapp.controller.authenticate.LoginRedirector; import edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean; @@ -327,6 +328,11 @@ public class Authenticate extends VitroHttpServlet { return; } + if (!getAuthenticator(request).isUserPermittedToLogin(user)) { + bean.setMessage(Message.LOGIN_DISABLED); + return; + } + if (!getAuthenticator(request).isCurrentPassword(user, password)) { bean.setMessage(Message.INCORRECT_PASSWORD); return; @@ -336,7 +342,13 @@ public class Authenticate extends VitroHttpServlet { if (user.isPasswordChangeRequired()) { transitionToForcedPasswordChange(request); } else { - transitionToLoggedIn(request, user); + try { + transitionToLoggedIn(request, user); + } catch (LoginNotPermitted e) { + // This should have been caught by isUserPermittedToLogin() + bean.setMessage(Message.LOGIN_DISABLED); + return; + } } } @@ -392,7 +404,13 @@ public class Authenticate extends VitroHttpServlet { } // New password is acceptable. Store it and go on. - transitionToLoggedIn(request, user, newPassword); + try { + transitionToLoggedIn(request, user, newPassword); + } catch (LoginNotPermitted e) { + // This should have been caught by isUserPermittedToLogin() + bean.setMessage(Message.LOGIN_DISABLED); + return; + } } /** @@ -424,7 +442,7 @@ public class Authenticate extends VitroHttpServlet { * State change: all requirements are satisfied. Log them in. */ private void transitionToLoggedIn(HttpServletRequest request, - UserAccount user) { + UserAccount user) throws LoginNotPermitted { log.debug("Completed login: " + user.getEmailAddress()); getAuthenticator(request).recordLoginAgainstUserAccount(user, AuthenticationSource.INTERNAL); @@ -435,7 +453,7 @@ public class Authenticate extends VitroHttpServlet { * log them in. */ private void transitionToLoggedIn(HttpServletRequest request, - UserAccount user, String newPassword) { + UserAccount user, String newPassword) throws LoginNotPermitted { log.debug("Completed login: " + user.getEmailAddress() + ", password changed."); getAuthenticator(request).recordNewPassword(user, newPassword); @@ -477,9 +495,10 @@ public class Authenticate extends VitroHttpServlet { response.sendRedirect(loginProcessPage); return; } - + /** - * Exit: user has completed the login. Redirect appropriately and clear the bean. + * Exit: user has completed the login. Redirect appropriately and clear the + * bean. */ private void showLoginComplete(HttpServletResponse response, VitroRequest vreq) throws IOException { @@ -497,12 +516,11 @@ public class Authenticate extends VitroHttpServlet { } private LoginRedirector getLoginRedirector(VitroRequest vreq) { - String afterLoginUrl = LoginProcessBean.getBean(vreq).getAfterLoginUrl(); + String afterLoginUrl = LoginProcessBean.getBean(vreq) + .getAfterLoginUrl(); return new LoginRedirector(vreq, afterLoginUrl); } - - /** Get a reference to the Authenticator. */ private Authenticator getAuthenticator(HttpServletRequest request) { return Authenticator.getInstance(request); 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 80b28c2d8..5c4c5017c 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 @@ -125,6 +125,10 @@ public class LoginProcessBean { public static final Message UNKNOWN_USERNAME = new Message( "The email or password you entered is incorrect.", MLevel.ERROR); + public static final Message LOGIN_DISABLED = new Message( + "User logins are temporarily disabled while the system is being maintained.", + MLevel.ERROR); + public static final Message INCORRECT_PASSWORD = new Message( "The email or password you entered is incorrect.", MLevel.ERROR); diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AuthenticatorStub.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AuthenticatorStub.java index f97d55032..84fba7c0d 100644 --- a/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AuthenticatorStub.java +++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AuthenticatorStub.java @@ -20,7 +20,7 @@ import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; public class AuthenticatorStub extends Authenticator { public static final String FACTORY_ATTRIBUTE_NAME = AuthenticatorFactory.class .getName(); - + // ---------------------------------------------------------------------- // factory - store this in the context. // @@ -97,6 +97,11 @@ public class AuthenticatorStub extends Authenticator { return usersByExternalAuthId.get(externalAuthId); } + @Override + public boolean isUserPermittedToLogin(UserAccount userAccount) { + return true; + } + @Override public boolean isCurrentPassword(UserAccount userAccount, String clearTextPassword) { diff --git a/webapp/web/templates/freemarker/body/login/adminLogin.ftl b/webapp/web/templates/freemarker/body/login/adminLogin.ftl index 6bf7228f2..d8d856dea 100644 --- a/webapp/web/templates/freemarker/body/login/adminLogin.ftl +++ b/webapp/web/templates/freemarker/body/login/adminLogin.ftl @@ -13,6 +13,10 @@ <#assign errorMessage = "No password supplied." /> #if> + <#if errorLoginDisabled??> + <#assign errorMessage = "User logins are temporarily disabled while the system is being maintained." /> + #if> + <#if errorLoginFailed??> <#assign errorMessage = "Email or Password was incorrect." /> #if>