NIHVIVO-2601 Create internal login for systems that only reveal the external authentication.
This commit is contained in:
parent
53c3c982bb
commit
7fed5babcf
6 changed files with 201 additions and 0 deletions
|
@ -1055,6 +1055,15 @@
|
||||||
<url-pattern>/programLogin</url-pattern>
|
<url-pattern>/programLogin</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>adminLogin</servlet-name>
|
||||||
|
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.authenticate.AdminLoginController</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>adminLogin</servlet-name>
|
||||||
|
<url-pattern>/admin/login</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
<servlet>
|
<servlet>
|
||||||
<servlet-name>logout</servlet-name>
|
<servlet-name>logout</servlet-name>
|
||||||
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.Logout</servlet-class>
|
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.Logout</servlet-class>
|
||||||
|
|
|
@ -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<String, Object> body = new HashMap<String, Object>();
|
||||||
|
body.put("controllerUrl", UrlBuilder.getUrl(URL_THIS));
|
||||||
|
body.put("username", "");
|
||||||
|
return new TemplateResponseValues(TEMPLATE_NAME, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ResponseValues showFormWithMessage(String messageCode) {
|
||||||
|
Map<String, Object> body = new HashMap<String, Object>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -72,6 +72,11 @@ public abstract class Authenticator {
|
||||||
*/
|
*/
|
||||||
public abstract List<String> getAssociatedIndividualUris(String username);
|
public abstract List<String> 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.
|
* Record a new password for the user.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -71,6 +71,16 @@ public class BasicAuthenticator extends Authenticator {
|
||||||
return md5NewPassword.equals(user.getMd5password());
|
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
|
@Override
|
||||||
public void recordNewPassword(String username, String newClearTextPassword) {
|
public void recordNewPassword(String username, String newClearTextPassword) {
|
||||||
User user = getUserByUsername(username);
|
User user = getUserByUsername(username);
|
||||||
|
|
|
@ -193,4 +193,10 @@ public class AuthenticatorStub extends Authenticator {
|
||||||
"AuthenticatorStub.recordLoginWithoutUserAccount() not implemented.");
|
"AuthenticatorStub.recordLoginWithoutUserAccount() not implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPasswordChangeRequired(String username) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"AuthenticatorStub.isPasswordChangeRequired() not implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
38
webapp/web/templates/freemarker/body/adminLogin.ftl
Normal file
38
webapp/web/templates/freemarker/body/adminLogin.ftl
Normal file
|
@ -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. -->
|
||||||
|
|
||||||
|
<section role="region">
|
||||||
|
<h2>Internal Login</h2>
|
||||||
|
|
||||||
|
<#if errorNoUser??>
|
||||||
|
<h3>No username supplied.</h3>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if errorNoPassword??>
|
||||||
|
<h3>No password supplied</h3>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if errorLoginFailed??>
|
||||||
|
<h3>Username or Password was incorrect.</h3>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if newPasswordRequired??>
|
||||||
|
<h3>This is your first time logging in. You must supply a new password.</h3>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Enter the username and password for your internal VIVO account.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<form action="${controllerUrl}">
|
||||||
|
<div> Username: <input type="text" name="username" value="${username}"/> </div>
|
||||||
|
<div> Password: <input type="text" name="password" /> </div>
|
||||||
|
|
||||||
|
<#if newPasswordRequired??>
|
||||||
|
<div>New Password: <input type="text" name="newPassword" /> </div>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<input type="submit" value="submit" />
|
||||||
|
</form>
|
||||||
|
</section>
|
Loading…
Add table
Reference in a new issue