From 7fed5babcfe0b16bdc88c34c79feab2931340e56 Mon Sep 17 00:00:00 2001 From: j2blake Date: Wed, 11 May 2011 16:02:43 +0000 Subject: [PATCH] NIHVIVO-2601 Create internal login for systems that only reveal the external authentication. --- webapp/config/web.xml | 9 ++ .../authenticate/AdminLoginController.java | 133 ++++++++++++++++++ .../authenticate/Authenticator.java | 5 + .../authenticate/BasicAuthenticator.java | 10 ++ .../authenticate/AuthenticatorStub.java | 6 + .../templates/freemarker/body/adminLogin.ftl | 38 +++++ 6 files changed, 201 insertions(+) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AdminLoginController.java create mode 100644 webapp/web/templates/freemarker/body/adminLogin.ftl diff --git a/webapp/config/web.xml b/webapp/config/web.xml index 7904cda31..4c495732e 100644 --- a/webapp/config/web.xml +++ b/webapp/config/web.xml @@ -1055,6 +1055,15 @@ /programLogin + + adminLogin + edu.cornell.mannlib.vitro.webapp.controller.authenticate.AdminLoginController + + + adminLogin + /admin/login + + logout edu.cornell.mannlib.vitro.webapp.controller.edit.Logout 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 new file mode 100644 index 000000000..5f1a6b780 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AdminLoginController.java @@ -0,0 +1,133 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.controller.authenticate; + +import static edu.cornell.mannlib.vedit.beans.LoginStatusBean.AuthenticationSource.INTERNAL; + +import java.util.HashMap; +import java.util.Map; + +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions; +import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; +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; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; +import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; + +/** + * Provide a "hidden" login page for systems where the Login Widget has been + * modified to only show the link to an External Authentication system. + * + * This page is only hidden because there is no link to it. Anyone who knows the + * URL can come here, but they need to pass Internal Authentication to proceed. + */ +public class AdminLoginController extends FreemarkerHttpServlet { + public static final String PARAMETER_USERNAME = "username"; + public static final String PARAMETER_PASSWORD = "password"; + public static final String PARAMETER_NEW_PASSWORD = "newPassword"; + + public static final String URL_THIS = "/admin/login"; + public static final String URL_HOME_PAGE = "/"; + + public static final String TEMPLATE_NAME = "adminLogin.ftl"; + + private static final String MESSAGE_NO_USERNAME = "errorNoUser"; + private static final String MESSAGE_NO_PASSWORD = "errorNoPassword"; + private static final String MESSAGE_LOGIN_FAILED = "errorLoginFailed"; + private static final String MESSAGE_NEW_PASSWORD_REQUIRED = "newPasswordRequired"; + + @Override + protected Actions requiredActions(VitroRequest vreq) { + return Actions.EMPTY; // No requirements to use this page. + } + + @Override + protected ResponseValues processRequest(VitroRequest vreq) { + return new Core(vreq).process(); + } + + /** + * A threadsafe holder for the controller logic. + */ + private static class Core { + private final Authenticator auth; + + private final String username; + private final String password; + private final String newPassword; + + public Core(VitroRequest vreq) { + this.auth = Authenticator.getInstance(vreq); + + this.username = nonNull(vreq.getParameter(PARAMETER_USERNAME)); + this.password = nonNull(vreq.getParameter(PARAMETER_PASSWORD)); + this.newPassword = nonNull(vreq + .getParameter(PARAMETER_NEW_PASSWORD)); + } + + public ResponseValues process() { + if (username.isEmpty() && password.isEmpty()) { + return showInitialForm(); + } + if (username.isEmpty()) { + return showFormWithMessage(MESSAGE_NO_USERNAME); + } + if (password.isEmpty()) { + return showFormWithMessage(MESSAGE_NO_PASSWORD); + } + if (newPasswordRequired() && newPassword.isEmpty()) { + return showFormWithMessage(MESSAGE_NEW_PASSWORD_REQUIRED); + } + + boolean loggedIn = tryToLogin(); + if (loggedIn) { + return goToHomePage(); + } + + return showFormWithMessage(MESSAGE_LOGIN_FAILED); + } + + private boolean newPasswordRequired() { + return auth.isCurrentPassword(username, password) + && auth.isPasswordChangeRequired(username); + } + + private boolean tryToLogin() { + if (auth.isCurrentPassword(username, password)) { + auth.recordLoginAgainstUserAccount(username, INTERNAL); + + if (auth.isPasswordChangeRequired(username)) { + auth.recordNewPassword(username, newPassword); + } + + return true; + } else { + return false; + } + } + + private ResponseValues showInitialForm() { + Map body = new HashMap(); + body.put("controllerUrl", UrlBuilder.getUrl(URL_THIS)); + body.put("username", ""); + return new TemplateResponseValues(TEMPLATE_NAME, body); + } + + private ResponseValues showFormWithMessage(String messageCode) { + Map body = new HashMap(); + body.put("controllerUrl", UrlBuilder.getUrl(URL_THIS)); + body.put("username", username); + body.put(messageCode, Boolean.TRUE); + return new TemplateResponseValues(TEMPLATE_NAME, body); + } + + private ResponseValues goToHomePage() { + return new RedirectResponseValues(URL_HOME_PAGE); + } + + private String nonNull(String s) { + return (s == null) ? "" : s; + } + } +} 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 9cb52a7c5..15df5bb25 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 @@ -72,6 +72,11 @@ public abstract class Authenticator { */ public abstract List getAssociatedIndividualUris(String username); + /** + * Is a password change needed when the user logs in? + */ + public abstract boolean isPasswordChangeRequired(String username); + /** * Record a new password for the 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 index 4544ed34a..ebbd5a09c 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 @@ -71,6 +71,16 @@ public class BasicAuthenticator extends Authenticator { return md5NewPassword.equals(user.getMd5password()); } + @Override + public boolean isPasswordChangeRequired(String username) { + User user = getUserDao().getUserByUsername(username); + if ((user != null) && (user.getLoginCount() == 0)) { + return true; + } else { + return false; + } + } + @Override public void recordNewPassword(String username, String newClearTextPassword) { User user = getUserByUsername(username); 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 dd4afa011..5488d91fb 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 @@ -193,4 +193,10 @@ public class AuthenticatorStub extends Authenticator { "AuthenticatorStub.recordLoginWithoutUserAccount() not implemented."); } + @Override + public boolean isPasswordChangeRequired(String username) { + throw new RuntimeException( + "AuthenticatorStub.isPasswordChangeRequired() not implemented."); + } + } diff --git a/webapp/web/templates/freemarker/body/adminLogin.ftl b/webapp/web/templates/freemarker/body/adminLogin.ftl new file mode 100644 index 000000000..af3898a30 --- /dev/null +++ b/webapp/web/templates/freemarker/body/adminLogin.ftl @@ -0,0 +1,38 @@ +<#-- $This file is distributed under the terms of the license in /doc/license.txt$ --> + +<#-- Template for the Fake External Authentication page. --> + +
+

Internal Login

+ + <#if errorNoUser??> +

No username supplied.

+ + + <#if errorNoPassword??> +

No password supplied

+ + + <#if errorLoginFailed??> +

Username or Password was incorrect.

+ + + <#if newPasswordRequired??> +

This is your first time logging in. You must supply a new password.

+ + +

+ Enter the username and password for your internal VIVO account. +

+ +
+
Username:
+
Password:
+ + <#if newPasswordRequired??> +
New Password:
+ + + +
+