NIHVIVO-638 Check in first phase of changes to the Login form and backend.
This commit is contained in:
parent
2253f889ed
commit
74c7660321
12 changed files with 999 additions and 342 deletions
|
@ -2,8 +2,12 @@
|
||||||
|
|
||||||
package edu.cornell.mannlib.vitro.webapp.controller.edit;
|
package edu.cornell.mannlib.vitro.webapp.controller.edit;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.util.Calendar;
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -13,6 +17,7 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
|
|
||||||
|
import org.apache.commons.codec.binary.Hex;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
@ -22,244 +27,529 @@ import edu.cornell.mannlib.vedit.beans.LoginFormBean;
|
||||||
import edu.cornell.mannlib.vitro.webapp.auth.policy.RoleBasedPolicy.AuthRole;
|
import edu.cornell.mannlib.vitro.webapp.auth.policy.RoleBasedPolicy.AuthRole;
|
||||||
import edu.cornell.mannlib.vitro.webapp.beans.User;
|
import edu.cornell.mannlib.vitro.webapp.beans.User;
|
||||||
import edu.cornell.mannlib.vitro.webapp.controller.Controllers;
|
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.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.UserDao;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
|
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.LoginEvent;
|
||||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.LoginLogoutEvent;
|
import edu.cornell.mannlib.vitro.webapp.dao.jena.LoginLogoutEvent;
|
||||||
|
|
||||||
public class Authenticate extends VitroHttpServlet {
|
public class Authenticate extends FreeMarkerHttpServlet {
|
||||||
private static final int DEFAULT_PORTAL_ID=1;
|
private static final Log log = LogFactory.getLog(Authenticate.class
|
||||||
public static final String USER_SESSION_MAP_ATTR = "userURISessionMap";
|
.getName());
|
||||||
private UserDao userDao = null;
|
|
||||||
private static final Log log = LogFactory.getLog(Authenticate.class.getName());
|
|
||||||
|
|
||||||
public void doPost( HttpServletRequest request, HttpServletResponse response ) {
|
/** The username field on the login form. */
|
||||||
try {
|
private static final String PARAMETER_USERNAME = "loginName";
|
||||||
HttpSession session = request.getSession();
|
|
||||||
if(session.isNew()){
|
|
||||||
session.setMaxInactiveInterval(300); // seconds, not milliseconds
|
|
||||||
}
|
|
||||||
userDao = ((WebappDaoFactory)session.getServletContext().getAttribute("webappDaoFactory")).getUserDao();
|
|
||||||
LoginFormBean f = (LoginFormBean) session.getAttribute( "loginHandler" );
|
|
||||||
|
|
||||||
//obtain a db connection and perform a db query
|
/** The password field on the login form. */
|
||||||
//ensuring that the username exists
|
private static final String PARAMETER_PASSWORD = "loginPassword";
|
||||||
|
|
||||||
// JCR 20040905 passing on portal home parameter
|
/** The new password field on the password change form. */
|
||||||
String portalIdStr=(portalIdStr=request.getParameter("home"))==null?String.valueOf(DEFAULT_PORTAL_ID):portalIdStr;
|
private static final String PARAMETER_NEW_PASSWORD = "newPassword";
|
||||||
//request.setAttribute("home",portalIdStr);
|
|
||||||
|
|
||||||
// Build the redirect URLs
|
/** The confirm password field on the password change form. */
|
||||||
String contextPath = request.getContextPath();
|
private static final String PARAMETER_CONFIRM_PASSWORD = "confirmPassword";
|
||||||
String urlParams = "?home=" + portalIdStr + "&login=block";
|
|
||||||
String loginUrl = contextPath + Controllers.LOGIN + urlParams;
|
|
||||||
String siteAdminUrl = contextPath + Controllers.SITE_ADMIN + urlParams;
|
|
||||||
|
|
||||||
if (userDao==null) {
|
/** If they are logging in, show them this form. */
|
||||||
f.setErrorMsg("loginPassword","unable to get UserDao");
|
public static final String TEMPLATE_LOGIN = "login/login.ftl";
|
||||||
f.setLoginStatus("no UserDao");
|
|
||||||
response.sendRedirect(loginUrl);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* used for encoding cleartext passwords sent via http before store in database
|
/** If they are changing their password on first login, show them this form. */
|
||||||
String loginPassword = "";
|
public static final String TEMPLATE_FORCE_PASSWORD_CHANGE = "login/forcedPasswordChange.ftl";
|
||||||
String passwordQuery = "SELECT PASSWORD('" + f.getLoginPassword() + "')";
|
|
||||||
ResultSet ps = stmt.executeQuery( passwordQuery );
|
|
||||||
while ( ps.next() ) {
|
|
||||||
loginPassword = ps.getString(1);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
String userEnteredPasswordAfterMd5Conversion=f.getLoginPassword(); // won't be null
|
|
||||||
if ( userEnteredPasswordAfterMd5Conversion.equals("") ) { // shouldn't get through JS form verification
|
|
||||||
f.setErrorMsg( "loginPassword","Please enter a password" );
|
|
||||||
f.setLoginStatus("bad_password");
|
|
||||||
response.sendRedirect(loginUrl);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
User user = userDao.getUserByUsername(f.getLoginName());
|
public static final String BODY_LOGIN_NAME = "loginName";
|
||||||
|
public static final String BODY_FORM_ACTION = "formAction";
|
||||||
|
public static final String BODY_ERROR_MESSAGE = "errorMessage";
|
||||||
|
|
||||||
if (user==null) {
|
/** If no portal is specified in the request, use this one. */
|
||||||
f.setErrorMsg( "loginName","No user found with username " + f.getLoginName() );
|
private static final int DEFAULT_PORTAL_ID = 1;
|
||||||
f.setLoginStatus("unknown_username");
|
|
||||||
response.sendRedirect(loginUrl);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// logic for authentication
|
/** Where do we find the User/Session map in the servlet context? */
|
||||||
// first check for new users (loginCount==0)
|
public static final String USER_SESSION_MAP_ATTR = "userURISessionMap";
|
||||||
// 1) cold (have username but haven't received initial password)
|
|
||||||
// 2) initial password has been set but user mis-typed it
|
|
||||||
// 3) correctly typed initial password and oldpassword set to provided password; have to enter a different one
|
|
||||||
// 4) entered same password again
|
|
||||||
// 5) entered a new private password, and bypass this stage because logincount set to 1
|
|
||||||
// then check for users DBA has set to require changing password (md5password is null, oldpassword is not)
|
|
||||||
//
|
|
||||||
// check password; dbMd5Password is md5password from database
|
|
||||||
if (user.getLoginCount() == 0 ) { // new user
|
|
||||||
if ( user.getMd5password() == null ) { // user is known but has not been given initial password
|
|
||||||
f.setErrorMsg( "loginPassword", "Please request a username and initial password via the link below" ); // store password in database but force immediate re-entry
|
|
||||||
f.setLoginStatus("first_login_no_password");
|
|
||||||
} else if (!user.getMd5password().equals( userEnteredPasswordAfterMd5Conversion )) { // mis-typed CCRP-provided initial password
|
|
||||||
if ( user.getOldPassword() == null ) { // did not make it through match of initially supplied password
|
|
||||||
f.setErrorMsg( "loginPassword", "Please try entering provided password again" );
|
|
||||||
f.setLoginStatus("first_login_mistyped");
|
|
||||||
} else if (user.getOldPassword().equals( userEnteredPasswordAfterMd5Conversion ) ) {
|
|
||||||
f.setErrorMsg( "loginPassword", "Please pick a different password from the one provided initially" );
|
|
||||||
f.setLoginStatus("changing_password_repeated_old");
|
|
||||||
} else { // successfully provided different, private password
|
|
||||||
f.setErrorMsg( "loginPassword", "Please re-enter new private password for confirmation" );
|
|
||||||
user.setMd5password(userEnteredPasswordAfterMd5Conversion);
|
|
||||||
user.setLoginCount(1);
|
|
||||||
userDao.updateUser(user);
|
|
||||||
f.setLoginStatus("changing_password");
|
|
||||||
}
|
|
||||||
} else if (f.getLoginStatus().equals("first_login_changing_password")) { // User has been prompted to change password, but has re-entered the original one
|
|
||||||
f.setErrorMsg( "loginPassword", "Please pick a different password from the one provided initially" ); // store password in database but force immediate re-entry
|
|
||||||
user.setOldPassword(user.getMd5password());
|
|
||||||
userDao.updateUser(user);
|
|
||||||
f.setLoginStatus("first_login_changing_password");
|
|
||||||
} else { // entered a password that matches initial md5password in database; now force them to change it
|
|
||||||
// oldpassword could be null or not null depending on number of mistries
|
|
||||||
f.setErrorMsg( "loginPassword", "Please now choose a private password" ); // store password in database but force immediate re-entry
|
|
||||||
user.setOldPassword(user.getMd5password());
|
|
||||||
userDao.updateUser(user);
|
|
||||||
f.setLoginStatus("first_login_changing_password");
|
|
||||||
}
|
|
||||||
response.sendRedirect(loginUrl);
|
|
||||||
return;
|
|
||||||
} else if ( user.getMd5password()==null ) { // DBA has forced entry of a new password for user with a loginCount > 0
|
|
||||||
if ( user.getOldPassword() != null && user.getOldPassword().equals( userEnteredPasswordAfterMd5Conversion ) ) {
|
|
||||||
f.setErrorMsg( "loginPassword", "Please pick a different password from your previous one" );
|
|
||||||
f.setLoginStatus("changing_password_repeated_old");
|
|
||||||
} else if (f.getLoginStatus().equals("changing_password")){ // User has been prompted to change password, but has re-entered the original one
|
|
||||||
f.setErrorMsg( "loginPassword", "Please pick a different password from the one provided initially" );
|
|
||||||
user.setMd5password(userEnteredPasswordAfterMd5Conversion);
|
|
||||||
userDao.updateUser(user);
|
|
||||||
f.setLoginStatus("changing_password");
|
|
||||||
} else { // User has entered provided password; now prompt to change password
|
|
||||||
f.setErrorMsg( "loginPassword", "Please re-enter new password for confirmation" );
|
|
||||||
user.setMd5password(userEnteredPasswordAfterMd5Conversion);
|
|
||||||
userDao.updateUser(user);
|
|
||||||
f.setLoginStatus("changing_password");
|
|
||||||
}
|
|
||||||
response.sendRedirect(loginUrl);
|
|
||||||
return;
|
|
||||||
} else if (!user.getMd5password().equals( userEnteredPasswordAfterMd5Conversion )) {
|
|
||||||
f.setErrorMsg( "loginPassword", "Incorrect password: try again");
|
|
||||||
f.setLoginStatus("bad_password");
|
|
||||||
f.setLoginPassword(""); // don't even reveal how many characters there were
|
|
||||||
response.sendRedirect(loginUrl);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//set the login bean properties from the database
|
/**
|
||||||
|
* Find out where they are in the login process, and check for progress. If
|
||||||
|
* they succeed in logging in, record the information. Show the next page.
|
||||||
|
*/
|
||||||
|
public void doPost(HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
|
||||||
//System.out.println("authenticated; setting login status in loginformbean");
|
VitroRequest vreq = new VitroRequest(request);
|
||||||
|
|
||||||
f.setUserURI(user.getURI());
|
User user = null;
|
||||||
f.setLoginStatus( "authenticated" );
|
|
||||||
f.setSessionId( session.getId());
|
|
||||||
f.setLoginRole( user.getRoleURI() );
|
|
||||||
try {
|
|
||||||
int loginRoleInt = Integer.decode(f.getLoginRole());
|
|
||||||
if( (loginRoleInt>1) && (session.isNew()) ) {
|
|
||||||
session.setMaxInactiveInterval(32000); // set longer timeout for editors
|
|
||||||
}
|
|
||||||
} catch (Exception e) {}
|
|
||||||
// TODO : might be a problem in next line - no ID
|
|
||||||
f.setLoginUserId( -2 );
|
|
||||||
//f.setEmailAddress ( email );
|
|
||||||
f.setLoginPassword( "" );
|
|
||||||
f.setErrorMsg( "loginPassword", "" ); // remove any error messages
|
|
||||||
f.setErrorMsg( "loginUsername", "" );
|
|
||||||
|
|
||||||
//System.out.println("updating loginCount and modTime");
|
try {
|
||||||
|
// Process any input from the login form.
|
||||||
Map<String,HttpSession> userURISessionMap = getUserURISessionMapFromContext( getServletContext() );
|
State entryState = getCurrentLoginState(vreq);
|
||||||
userURISessionMap.put( user.getURI(), request.getSession() );
|
log.debug("State on entry: " + entryState);
|
||||||
|
|
||||||
sendLoginNotifyEvent(new LoginEvent( user.getURI() ), getServletContext(), session);
|
|
||||||
|
|
||||||
user.setLoginCount(user.getLoginCount()+1);
|
|
||||||
userDao.updateUser(user);
|
|
||||||
|
|
||||||
if ( user.getLoginCount() == 2 ) { // first login
|
switch (entryState) {
|
||||||
Calendar cal = Calendar.getInstance();
|
case LOGGING_IN:
|
||||||
user.setFirstTime(cal.getTime());
|
user = checkLoginProgress(vreq);
|
||||||
userDao.updateUser(user);
|
if (user != null) {
|
||||||
}
|
whatNextForThisGuy(vreq, user);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FORCED_PASSWORD_CHANGE:
|
||||||
|
user = checkChangeProgress(vreq);
|
||||||
|
if (user != null) {
|
||||||
|
recordSuccessfulPasswordChange(vreq, user);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
// Figure out where they should be, and redirect.
|
||||||
*If you set a postLoginRequest attribute in the session and forward to about
|
State exitState = getCurrentLoginState(vreq);
|
||||||
*then this will attempt to send the client back to the original page after the login.
|
log.debug("State on exit: " + exitState);
|
||||||
*/
|
|
||||||
String forwardStr = (String) request.getSession().getAttribute("postLoginRequest");
|
switch (exitState) {
|
||||||
request.getSession().removeAttribute("postLoginRequest");
|
case LOGGED_IN:
|
||||||
if (forwardStr == null) {
|
redirectLoggedInUser(vreq, response);
|
||||||
String contextPostLoginRequest = (String) getServletContext().getAttribute("postLoginRequest");
|
break;
|
||||||
if (contextPostLoginRequest != null) {
|
default:
|
||||||
forwardStr = (contextPostLoginRequest.indexOf(":") == -1)
|
showLoginScreen(vreq, response);
|
||||||
? request.getContextPath() + contextPostLoginRequest
|
break;
|
||||||
: contextPostLoginRequest;
|
}
|
||||||
}
|
} catch (Exception e) {
|
||||||
}
|
showSystemError(e, response);
|
||||||
|
}
|
||||||
if( AuthRole.USER.roleUri().equals( user.getRoleURI() ) ){
|
}
|
||||||
/* if this is a self editor, redirect the to their page */
|
|
||||||
List<String> uris = userDao.getIndividualsUserMayEditAs(user.getURI());
|
/**
|
||||||
if( uris != null && uris.size() > 0 ){
|
* They are logging in. Are they successful?
|
||||||
forwardStr = request.getContextPath() + "/individual?uri=" + URLEncoder.encode(uris.get(0), "UTF-8");
|
*/
|
||||||
}
|
private User checkLoginProgress(HttpServletRequest request) {
|
||||||
}
|
String username = request.getParameter(PARAMETER_USERNAME);
|
||||||
|
String password = request.getParameter(PARAMETER_PASSWORD);
|
||||||
|
|
||||||
if (forwardStr != null) {
|
LoginProcessBean bean = getLoginProcessBean(request);
|
||||||
response.sendRedirect(forwardStr);
|
bean.clearMessage();
|
||||||
} else {
|
log.trace("username=" + username + ", password=" + password + ", bean="
|
||||||
response.sendRedirect(siteAdminUrl);
|
+ bean);
|
||||||
//RequestDispatcher rd = getServletContext().getRequestDispatcher(url);
|
|
||||||
//rd.forward(request,response);
|
if ((username == null) || username.isEmpty()) {
|
||||||
}
|
bean.setMessage(Message.NO_USERNAME);
|
||||||
} catch (Throwable t) {
|
return null;
|
||||||
log.error( t.getMessage() );
|
} else {
|
||||||
t.printStackTrace();
|
bean.setUsername(username);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
User user = getUserDao(request).getUserByUsername(username);
|
||||||
|
log.trace("User is " + (user == null ? "null" : user.getURI()));
|
||||||
|
|
||||||
|
if (user == null) {
|
||||||
|
bean.setMessage(Message.UNKNOWN_USERNAME, username);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((password == null) || password.isEmpty()) {
|
||||||
|
bean.setMessage(Message.NO_PASSWORD);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String md5Password = applyMd5Encoding(password);
|
||||||
|
|
||||||
|
if (!md5Password.equals(user.getMd5password())) {
|
||||||
|
log.trace("Encoded passwords don't match: right="
|
||||||
|
+ user.getMd5password() + ", wrong=" + md5Password);
|
||||||
|
bean.setMessage(Message.INCORRECT_PASSWORD);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Successfully applied username and password. Are we forcing a password
|
||||||
|
* change, or is this guy logged in?
|
||||||
|
*/
|
||||||
|
private void whatNextForThisGuy(HttpServletRequest request, User user) {
|
||||||
|
if (user.getLoginCount() == 0) {
|
||||||
|
log.debug("Forcing first-time password change");
|
||||||
|
LoginProcessBean bean = getLoginProcessBean(request);
|
||||||
|
bean.setState(State.FORCED_PASSWORD_CHANGE);
|
||||||
|
} else {
|
||||||
|
recordLoginInfo(request, user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* They are changing password. Are they successful?
|
||||||
|
*/
|
||||||
|
private User checkChangeProgress(HttpServletRequest request) {
|
||||||
|
String newPassword = request.getParameter(PARAMETER_NEW_PASSWORD);
|
||||||
|
String confirm = request.getParameter(PARAMETER_CONFIRM_PASSWORD);
|
||||||
|
LoginProcessBean bean = getLoginProcessBean(request);
|
||||||
|
bean.clearMessage();
|
||||||
|
log.trace("newPassword=" + newPassword + ", confirm=" + confirm
|
||||||
|
+ ", bean=" + bean);
|
||||||
|
|
||||||
|
if ((newPassword == null) || newPassword.isEmpty()) {
|
||||||
|
bean.setMessage(Message.NO_NEW_PASSWORD);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newPassword.equals(confirm)) {
|
||||||
|
bean.setMessage(Message.MISMATCH_PASSWORD);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((newPassword.length() < User.MIN_PASSWORD_LENGTH)
|
||||||
|
|| (newPassword.length() > User.MAX_PASSWORD_LENGTH)) {
|
||||||
|
bean.setMessage(Message.PASSWORD_LENGTH, User.MIN_PASSWORD_LENGTH,
|
||||||
|
User.MAX_PASSWORD_LENGTH);
|
||||||
|
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())) {
|
||||||
|
bean.setMessage(Message.USING_OLD_PASSWORD);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store the changed password. They're not logged in yet, but they no longer
|
||||||
|
* need to change their password.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
user.setLoginCount(user.getLoginCount() + 1);
|
||||||
|
getUserDao(request).updateUser(user);
|
||||||
|
log.debug("Completed first-time password change.");
|
||||||
|
|
||||||
|
LoginProcessBean bean = getLoginProcessBean(request);
|
||||||
|
bean.setState(State.LOGGING_IN);
|
||||||
|
bean.setMessage(Message.PASSWORD_CHANGE_SAVED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user provided the correct information, and changed the password if
|
||||||
|
* that was required. Record that they have logged in.
|
||||||
|
*/
|
||||||
|
private void recordLoginInfo(HttpServletRequest request, User user) {
|
||||||
|
log.debug("Completed login.");
|
||||||
|
|
||||||
|
HttpSession session = request.getSession();
|
||||||
|
|
||||||
|
// Put the login info into the 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);
|
||||||
|
|
||||||
|
// Remove the login process info from the session.
|
||||||
|
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.
|
||||||
|
session.setMaxInactiveInterval(300); // seconds, not milliseconds
|
||||||
|
try {
|
||||||
|
if ((int) Integer.decode(lfb.getLoginRole()) > 1) {
|
||||||
|
session.setMaxInactiveInterval(32000);
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
// No problem - leave it at the default.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record the user in the user/Session map.
|
||||||
|
Map<String, HttpSession> userURISessionMap = getUserURISessionMapFromContext(getServletContext());
|
||||||
|
userURISessionMap.put(user.getURI(), request.getSession());
|
||||||
|
|
||||||
|
// Notify the other users of this model.
|
||||||
|
sendLoginNotifyEvent(new LoginEvent(user.getURI()),
|
||||||
|
getServletContext(), session);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User is in the login process. Show them the login screen.
|
||||||
|
*/
|
||||||
|
private void showLoginScreen(VitroRequest vreq, HttpServletResponse response)
|
||||||
|
throws IOException {
|
||||||
|
response.sendRedirect(getLoginScreenUrl(vreq));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User is logged in. They might go to:
|
||||||
|
* <ul>
|
||||||
|
* <li>A one-time redirect, stored in the session, if they had tried to
|
||||||
|
* bookmark to a page that requires login.</li>
|
||||||
|
* <li>An application-wide redirect, stored in the servlet context.</li>
|
||||||
|
* <li>Their home page, if they are a self-editor.</li>
|
||||||
|
* <li>The site admin page.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
private void redirectLoggedInUser(HttpServletRequest request,
|
||||||
|
HttpServletResponse response) throws IOException,
|
||||||
|
UnsupportedEncodingException {
|
||||||
|
// Did they have a one-time redirect stored on the session?
|
||||||
|
String sessionRedirect = (String) request.getSession().getAttribute(
|
||||||
|
"postLoginRequest");
|
||||||
|
if (sessionRedirect != null) {
|
||||||
|
request.getSession().removeAttribute("postLoginRequest");
|
||||||
|
log.debug("User is logged in. Redirect by session to "
|
||||||
|
+ sessionRedirect);
|
||||||
|
response.sendRedirect(sessionRedirect);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is there a login-redirect stored in the application as a whole?
|
||||||
|
// It could lead to another page in this app, or to any random URL.
|
||||||
|
String contextRedirect = (String) getServletContext().getAttribute(
|
||||||
|
"postLoginRequest");
|
||||||
|
if (contextRedirect != null) {
|
||||||
|
log.debug("User is logged in. Redirect by application to "
|
||||||
|
+ contextRedirect);
|
||||||
|
if (contextRedirect.indexOf(":") == -1) {
|
||||||
|
response.sendRedirect(request.getContextPath()
|
||||||
|
+ contextRedirect);
|
||||||
|
} else {
|
||||||
|
response.sendRedirect(contextRedirect);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the user is a self-editor, send them to their home page.
|
||||||
|
User user = getLoggedInUser(request);
|
||||||
|
if (AuthRole.USER.roleUri().equals(user.getRoleURI())) {
|
||||||
|
UserDao userDao = getUserDao(request);
|
||||||
|
if (userDao != null) {
|
||||||
|
List<String> uris = userDao.getIndividualsUserMayEditAs(user
|
||||||
|
.getURI());
|
||||||
|
if (uris != null && uris.size() > 0) {
|
||||||
|
log.debug("User is logged in. Redirect as self-editor to "
|
||||||
|
+ sessionRedirect);
|
||||||
|
String userHomePage = request.getContextPath()
|
||||||
|
+ "/individual?uri="
|
||||||
|
+ URLEncoder.encode(uris.get(0), "UTF-8");
|
||||||
|
log.debug("User is logged in. Redirect as self-editor to "
|
||||||
|
+ sessionRedirect);
|
||||||
|
response.sendRedirect(userHomePage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If nothing else applies, send them to the Site Admin page.
|
||||||
|
log.debug("User is logged in. Redirect to site admin page.");
|
||||||
|
response.sendRedirect(getSiteAdminUrl(request));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* There has been an unexpected exception. Complain mightily.
|
||||||
|
*/
|
||||||
|
private void showSystemError(Exception e, HttpServletResponse response) {
|
||||||
|
log.error("Unexpected error in login process" + e);
|
||||||
|
try {
|
||||||
|
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
||||||
|
} catch (IOException e1) {
|
||||||
|
log.error(e1, e1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where are we in the process? Logged in? Not? Somewhere in between?
|
||||||
|
*/
|
||||||
|
private State getCurrentLoginState(HttpServletRequest request) {
|
||||||
|
HttpSession session = request.getSession(false);
|
||||||
|
if (session == null) {
|
||||||
|
return State.NOWHERE;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoginFormBean lfb = (LoginFormBean) session
|
||||||
|
.getAttribute("loginHandler");
|
||||||
|
if ((lfb != null) && (lfb.getLoginStatus().equals("authenticated"))) {
|
||||||
|
return State.LOGGED_IN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getLoginProcessBean(request).getState();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What user are we logged in as?
|
||||||
|
*/
|
||||||
|
private User getLoggedInUser(HttpServletRequest request) {
|
||||||
|
UserDao userDao = getUserDao(request);
|
||||||
|
if (userDao == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpSession session = request.getSession(false);
|
||||||
|
if (session == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoginFormBean lfb = (LoginFormBean) session
|
||||||
|
.getAttribute("loginHandler");
|
||||||
|
if (lfb == null) {
|
||||||
|
log.debug("getLoggedInUser: not logged in");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return userDao.getUserByUsername(lfb.getLoginName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a reference to the {@link UserDao}, or <code>null</code>.
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** What's the URL for the login screen? */
|
||||||
|
private String getLoginScreenUrl(HttpServletRequest request) {
|
||||||
|
String contextPath = request.getContextPath();
|
||||||
|
String urlParams = "?home=" + getPortalIdString(request)
|
||||||
|
+ "&login=block";
|
||||||
|
return contextPath + Controllers.LOGIN + urlParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** What's the URL for the site admin screen? */
|
||||||
|
private String getSiteAdminUrl(HttpServletRequest request) {
|
||||||
|
String contextPath = request.getContextPath();
|
||||||
|
String urlParams = "?home=" + getPortalIdString(request)
|
||||||
|
+ "&login=block";
|
||||||
|
return contextPath + Controllers.SITE_ADMIN + urlParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What portal are we currently in?
|
||||||
|
*/
|
||||||
|
private String getPortalIdString(HttpServletRequest request) {
|
||||||
|
String portalIdParameter = request.getParameter("home");
|
||||||
|
if (portalIdParameter == null) {
|
||||||
|
return String.valueOf(DEFAULT_PORTAL_ID);
|
||||||
|
} else {
|
||||||
|
return portalIdParameter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How is the login process coming along?
|
||||||
|
*/
|
||||||
|
private LoginProcessBean getLoginProcessBean(HttpServletRequest request) {
|
||||||
|
HttpSession session = request.getSession();
|
||||||
|
|
||||||
|
LoginProcessBean bean = (LoginProcessBean) session
|
||||||
|
.getAttribute(LoginProcessBean.SESSION_ATTRIBUTE);
|
||||||
|
|
||||||
|
if (bean == null) {
|
||||||
|
bean = new LoginProcessBean();
|
||||||
|
session.setAttribute(LoginProcessBean.SESSION_ATTRIBUTE, bean);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode this password for storage in the database. Apply an MD5 encoding,
|
||||||
|
* and store the result as a string of hex digits.
|
||||||
|
*/
|
||||||
|
private String applyMd5Encoding(String password) {
|
||||||
|
try {
|
||||||
|
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||||
|
byte[] digest = md.digest(password.getBytes());
|
||||||
|
char[] hexChars = Hex.encodeHex(digest);
|
||||||
|
return new String(hexChars).toUpperCase();
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
// This can't happen with a normal Java runtime.
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
// Public utility methods.
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The servlet context should contain a map from User URIs to
|
||||||
|
* {@link HttpSession}s. Get a reference to it, creating it if necessary.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static Map<String, HttpSession> getUserURISessionMapFromContext(
|
||||||
|
ServletContext ctx) {
|
||||||
|
Map<String, HttpSession> m = (Map<String, HttpSession>) ctx
|
||||||
|
.getAttribute(USER_SESSION_MAP_ATTR);
|
||||||
|
if (m == null) {
|
||||||
|
m = new HashMap<String, HttpSession>();
|
||||||
|
ctx.setAttribute(USER_SESSION_MAP_ATTR, m);
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Let everyone know that somebody has logged in or logged out.
|
||||||
|
*/
|
||||||
|
public static void sendLoginNotifyEvent(LoginLogoutEvent event,
|
||||||
|
ServletContext context, HttpSession session) {
|
||||||
|
if (event == null) {
|
||||||
|
log.warn("Unable to notify audit model of login "
|
||||||
|
+ "because a null event was passed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OntModel jenaOntModel = (OntModel) session.getAttribute("jenaOntModel");
|
||||||
|
if (jenaOntModel == null) {
|
||||||
|
jenaOntModel = (OntModel) context.getAttribute("jenaOntModel");
|
||||||
|
}
|
||||||
|
if (jenaOntModel == null) {
|
||||||
|
log.error("Unable to notify audit model of login event "
|
||||||
|
+ "because no model could be found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jenaOntModel.getBaseModel().notifyEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
public static void sendLoginNotifyEvent(LoginLogoutEvent event, ServletContext context, HttpSession session){
|
|
||||||
Object sessionOntModel = null;
|
|
||||||
if( session != null )
|
|
||||||
sessionOntModel = session.getAttribute("jenaOntModel");
|
|
||||||
Object contextOntModel = null;
|
|
||||||
if( context != null )
|
|
||||||
contextOntModel = context.getAttribute("jenaOntModel");
|
|
||||||
|
|
||||||
OntModel jenaOntModel =
|
|
||||||
( (sessionOntModel != null && sessionOntModel instanceof OntModel)
|
|
||||||
? (OntModel)sessionOntModel: (OntModel) context.getAttribute("jenaOntModel") );
|
|
||||||
|
|
||||||
if( jenaOntModel == null ){
|
|
||||||
log.error( "Unable to notify audit model of login event because no model could be found");
|
|
||||||
} else {
|
|
||||||
if( event == null ){
|
|
||||||
log.warn("Unable to notify audit model of login because a null event was passed");
|
|
||||||
}else{
|
|
||||||
jenaOntModel.getBaseModel().notifyEvent( event );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Map<String,HttpSession> getUserURISessionMapFromContext( ServletContext ctx ) {
|
|
||||||
Map<String,HttpSession> m = (Map<String,HttpSession>) ctx.getAttribute( USER_SESSION_MAP_ATTR );
|
|
||||||
if ( m == null ) {
|
|
||||||
m = new HashMap<String,HttpSession>();
|
|
||||||
ctx.setAttribute( USER_SESSION_MAP_ATTR, m );
|
|
||||||
}
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ public class UserEditController extends BaseEditController {
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayList results = new ArrayList();
|
ArrayList results = new ArrayList();
|
||||||
results.add("User");
|
results.add("Email address");
|
||||||
results.add("first name");
|
results.add("first name");
|
||||||
results.add("last name");
|
results.add("last name");
|
||||||
results.add("login count");
|
results.add("login count");
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.controller.login;
|
||||||
|
|
||||||
|
import java.text.MessageFormat;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where are we in the process of logging on? What message should we show to the
|
||||||
|
* user?
|
||||||
|
*/
|
||||||
|
public class LoginProcessBean {
|
||||||
|
private static Object[] NO_ARGUMENTS = new Object[0];
|
||||||
|
|
||||||
|
public static final String SESSION_ATTRIBUTE = LoginProcessBean.class
|
||||||
|
.getName();
|
||||||
|
|
||||||
|
public enum State {
|
||||||
|
NOWHERE, LOGGING_IN, FORCED_PASSWORD_CHANGE, LOGGED_IN
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum MLevel {
|
||||||
|
NONE, INFO, ERROR
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Message {
|
||||||
|
NO_MESSAGE("", MLevel.NONE),
|
||||||
|
|
||||||
|
PASSWORD_CHANGE_SAVED("Your password has been saved.<br/>"
|
||||||
|
+ "Please log in.", MLevel.INFO),
|
||||||
|
|
||||||
|
NO_USERNAME("Please enter your email address.", MLevel.ERROR),
|
||||||
|
|
||||||
|
NO_PASSWORD("Please enter your password.", MLevel.ERROR),
|
||||||
|
|
||||||
|
UNKNOWN_USERNAME("The email or password you entered is incorrect.",
|
||||||
|
MLevel.ERROR),
|
||||||
|
|
||||||
|
INCORRECT_PASSWORD("The email or password you entered is incorrect.",
|
||||||
|
MLevel.ERROR),
|
||||||
|
|
||||||
|
NO_NEW_PASSWORD("Please enter your new password.", MLevel.ERROR),
|
||||||
|
|
||||||
|
MISMATCH_PASSWORD("The passwords entered do not match.", MLevel.ERROR),
|
||||||
|
|
||||||
|
PASSWORD_LENGTH(
|
||||||
|
"Please enter a password between {0} and {1} characters long",
|
||||||
|
MLevel.ERROR),
|
||||||
|
|
||||||
|
USING_OLD_PASSWORD("Please choose a different password from the "
|
||||||
|
+ "temporary one provided initially.", MLevel.ERROR);
|
||||||
|
|
||||||
|
private final String format;
|
||||||
|
private final MLevel messageLevel;
|
||||||
|
|
||||||
|
Message(String format, MLevel messageLevel) {
|
||||||
|
this.format = format;
|
||||||
|
this.messageLevel = messageLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getFormat() {
|
||||||
|
return this.format;
|
||||||
|
}
|
||||||
|
|
||||||
|
MLevel getMessageLevel() {
|
||||||
|
return this.messageLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
String formatMessage(Object[] args) {
|
||||||
|
return new MessageFormat(this.format).format(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Where are we in the process? */
|
||||||
|
private State currentState = State.NOWHERE;
|
||||||
|
|
||||||
|
/** What message should we display on the screen? */
|
||||||
|
private Message message = Message.NO_MESSAGE;
|
||||||
|
|
||||||
|
/** What arguments are needed to format the message? */
|
||||||
|
private Object[] messageArguments = NO_ARGUMENTS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
private String username = "";
|
||||||
|
|
||||||
|
public void setState(State newState) {
|
||||||
|
this.currentState = newState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public State getState() {
|
||||||
|
return currentState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearMessage() {
|
||||||
|
this.message = Message.NO_MESSAGE;
|
||||||
|
this.messageArguments = NO_ARGUMENTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMessage(Message message, Object... args) {
|
||||||
|
this.message = message;
|
||||||
|
this.messageArguments = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInfoMessage() {
|
||||||
|
if (message.getMessageLevel() == MLevel.INFO) {
|
||||||
|
return message.formatMessage(messageArguments);
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getErrorMessage() {
|
||||||
|
if (message.getMessageLevel() == MLevel.ERROR) {
|
||||||
|
return message.formatMessage(messageArguments);
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return username;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUsername(String username) {
|
||||||
|
this.username = username;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "LoginProcessBean[state=" + currentState + ", message="
|
||||||
|
+ message + ", messageArguments="
|
||||||
|
+ Arrays.deepToString(messageArguments) + ", username="
|
||||||
|
+ username + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,225 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.controller.login;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
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.vitro.webapp.controller.VitroRequest;
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.edit.Authenticate;
|
||||||
|
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.login.LoginProcessBean.State;
|
||||||
|
import freemarker.template.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A temporary means of displaying the Login templates within the SiteAdmin
|
||||||
|
* form.
|
||||||
|
*
|
||||||
|
* This class contains stuff that I swiped from {@link Authenticate}. The base
|
||||||
|
* class, {@link LoginTemplateHelperBase}, contains stuff that I swiped from
|
||||||
|
* {@link FreeMarkerHttpServlet}.
|
||||||
|
*/
|
||||||
|
public class LoginTemplateHelper extends LoginTemplateHelperBase {
|
||||||
|
private static final Log log = LogFactory.getLog(LoginTemplateHelper.class);
|
||||||
|
|
||||||
|
/** If they are logging in, show them this form. */
|
||||||
|
public static final String TEMPLATE_LOGIN = "login/login.ftl";
|
||||||
|
|
||||||
|
/** If they are changing their password on first login, show them this form. */
|
||||||
|
public static final String TEMPLATE_FORCE_PASSWORD_CHANGE = "login/forcedPasswordChange.ftl";
|
||||||
|
|
||||||
|
public static final String BODY_LOGIN_NAME = "loginName";
|
||||||
|
public static final String BODY_FORM_ACTION = "formAction";
|
||||||
|
public static final String BODY_INFO_MESSAGE = "infoMessage";
|
||||||
|
public static final String BODY_ERROR_MESSAGE = "errorMessage";
|
||||||
|
public static final String BODY_ALERT_ICON_URL = "alertImageUrl";
|
||||||
|
|
||||||
|
/** Use this icon for an info message. */
|
||||||
|
public static final String URL_INFO_ICON = "/images/iconAlert.png";
|
||||||
|
|
||||||
|
/** Use this icon for an error message. */
|
||||||
|
public static final String URL_ERROR_ICON = "/images/iconAlert.png";
|
||||||
|
|
||||||
|
/** If no portal is specified in the request, use this one. */
|
||||||
|
private static final int DEFAULT_PORTAL_ID = 1;
|
||||||
|
|
||||||
|
public LoginTemplateHelper(HttpServletRequest req) {
|
||||||
|
super(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String showLoginPage(HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
VitroRequest vreq = new VitroRequest(request);
|
||||||
|
|
||||||
|
State state = getCurrentLoginState(vreq);
|
||||||
|
log.debug("State on exit: " + state);
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case LOGGED_IN:
|
||||||
|
return "";
|
||||||
|
case FORCED_PASSWORD_CHANGE:
|
||||||
|
return doTemplate(vreq, showPasswordChangeScreen(vreq));
|
||||||
|
default:
|
||||||
|
return doTemplate(vreq, showLoginScreen(vreq));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e);
|
||||||
|
return "<h2>Internal server error:<br/>" + e + "</h2>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User is just starting the login process. Be sure that we have a
|
||||||
|
* {@link LoginProcessBean} with the correct status. Show them the login
|
||||||
|
* screen.
|
||||||
|
*/
|
||||||
|
private TemplateResponseValues showLoginScreen(VitroRequest vreq)
|
||||||
|
throws IOException {
|
||||||
|
LoginProcessBean bean = getLoginProcessBean(vreq);
|
||||||
|
bean.setState(State.LOGGING_IN);
|
||||||
|
log.trace("Going to login screen: " + bean);
|
||||||
|
|
||||||
|
TemplateResponseValues trv = new TemplateResponseValues(TEMPLATE_LOGIN);
|
||||||
|
trv.put(BODY_FORM_ACTION, getAuthenticateUrl(vreq));
|
||||||
|
trv.put(BODY_LOGIN_NAME, bean.getUsername());
|
||||||
|
|
||||||
|
String infoMessage = bean.getInfoMessage();
|
||||||
|
if (!infoMessage.isEmpty()) {
|
||||||
|
trv.put(BODY_INFO_MESSAGE, infoMessage);
|
||||||
|
trv.put(BODY_ALERT_ICON_URL, UrlBuilder.getUrl(URL_INFO_ICON));
|
||||||
|
}
|
||||||
|
String errorMessage = bean.getErrorMessage();
|
||||||
|
if (!errorMessage.isEmpty()) {
|
||||||
|
trv.put(BODY_ERROR_MESSAGE, errorMessage);
|
||||||
|
trv.put(BODY_ALERT_ICON_URL, UrlBuilder.getUrl(URL_ERROR_ICON));
|
||||||
|
}
|
||||||
|
return trv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user has given the correct password, but now they are required to
|
||||||
|
* change it.
|
||||||
|
*/
|
||||||
|
private TemplateResponseValues showPasswordChangeScreen(VitroRequest vreq) {
|
||||||
|
LoginProcessBean bean = getLoginProcessBean(vreq);
|
||||||
|
bean.setState(State.FORCED_PASSWORD_CHANGE);
|
||||||
|
log.trace("Going to password change screen: " + bean);
|
||||||
|
|
||||||
|
TemplateResponseValues trv = new TemplateResponseValues(
|
||||||
|
TEMPLATE_FORCE_PASSWORD_CHANGE);
|
||||||
|
trv.put(BODY_FORM_ACTION, getAuthenticateUrl(vreq));
|
||||||
|
|
||||||
|
String errorMessage = bean.getErrorMessage();
|
||||||
|
if (!errorMessage.isEmpty()) {
|
||||||
|
trv.put(BODY_ERROR_MESSAGE, errorMessage);
|
||||||
|
trv.put(BODY_ALERT_ICON_URL, UrlBuilder.getUrl(URL_ERROR_ICON));
|
||||||
|
}
|
||||||
|
return trv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We processed a response, and want to show a template.
|
||||||
|
*/
|
||||||
|
private String doTemplate(VitroRequest vreq, TemplateResponseValues values) {
|
||||||
|
// Set it up like FreeMarkerHttpServlet.doGet() would do.
|
||||||
|
Configuration config = getConfig(vreq);
|
||||||
|
Map<String, Object> sharedVariables = getSharedVariables(vreq);
|
||||||
|
Map<String, Object> root = new HashMap<String, Object>(sharedVariables);
|
||||||
|
Map<String, Object> body = new HashMap<String, Object>(sharedVariables);
|
||||||
|
setUpRoot(vreq, root);
|
||||||
|
|
||||||
|
// Add the values that we got, and merge to the template.
|
||||||
|
body.putAll(values.getBodyMap());
|
||||||
|
return mergeBodyToTemplate(values.getTemplateName(), body, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where are we in the process? Logged in? Not? Somewhere in between?
|
||||||
|
*/
|
||||||
|
private State getCurrentLoginState(HttpServletRequest request) {
|
||||||
|
HttpSession session = request.getSession(false);
|
||||||
|
if (session == null) {
|
||||||
|
return State.NOWHERE;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoginFormBean lfb = (LoginFormBean) session
|
||||||
|
.getAttribute("loginHandler");
|
||||||
|
if ((lfb != null) && (lfb.getLoginStatus().equals("authenticated"))) {
|
||||||
|
return State.LOGGED_IN;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getLoginProcessBean(request).getState();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How is the login process coming along?
|
||||||
|
*/
|
||||||
|
private LoginProcessBean getLoginProcessBean(HttpServletRequest request) {
|
||||||
|
HttpSession session = request.getSession();
|
||||||
|
|
||||||
|
LoginProcessBean bean = (LoginProcessBean) session
|
||||||
|
.getAttribute(LoginProcessBean.SESSION_ATTRIBUTE);
|
||||||
|
|
||||||
|
if (bean == null) {
|
||||||
|
bean = new LoginProcessBean();
|
||||||
|
session.setAttribute(LoginProcessBean.SESSION_ATTRIBUTE, bean);
|
||||||
|
}
|
||||||
|
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** What's the URL for this servlet? */
|
||||||
|
private String getAuthenticateUrl(HttpServletRequest request) {
|
||||||
|
String contextPath = request.getContextPath();
|
||||||
|
String urlParams = "?home=" + getPortalIdString(request)
|
||||||
|
+ "&login=block";
|
||||||
|
return contextPath + "/authenticate" + urlParams;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What portal are we currently in?
|
||||||
|
*/
|
||||||
|
private String getPortalIdString(HttpServletRequest request) {
|
||||||
|
String portalIdParameter = request.getParameter("home");
|
||||||
|
if (portalIdParameter == null) {
|
||||||
|
return String.valueOf(DEFAULT_PORTAL_ID);
|
||||||
|
} else {
|
||||||
|
return portalIdParameter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds the name of the template and the map of values.
|
||||||
|
*/
|
||||||
|
private static class TemplateResponseValues {
|
||||||
|
private final String templateName;
|
||||||
|
private final Map<String, Object> bodyMap = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
public TemplateResponseValues(String templateName) {
|
||||||
|
this.templateName = templateName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TemplateResponseValues put(String key, Object value) {
|
||||||
|
this.bodyMap.put(key, value);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<? extends String, ? extends Object> getBodyMap() {
|
||||||
|
return Collections.unmodifiableMap(this.bodyMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTemplateName() {
|
||||||
|
return this.templateName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
|
||||||
|
|
||||||
|
package edu.cornell.mannlib.vitro.webapp.controller.login;
|
||||||
|
|
||||||
|
import javax.servlet.ServletContext;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreeMarkerHttpServlet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A temporary means of displaying the Login templates within the SiteAdmin
|
||||||
|
* form.
|
||||||
|
*
|
||||||
|
* The constructor insures that the ServletContext is set.
|
||||||
|
*/
|
||||||
|
public class LoginTemplateHelperBase extends FreeMarkerHttpServlet {
|
||||||
|
private final ServletContext servletContext;
|
||||||
|
|
||||||
|
LoginTemplateHelperBase(HttpServletRequest req) {
|
||||||
|
this.servletContext = req.getSession().getServletContext();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServletContext getServletContext() {
|
||||||
|
return servletContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
BIN
webapp/web/images/iconAlert.png
Normal file
BIN
webapp/web/images/iconAlert.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
|
@ -2,120 +2,14 @@
|
||||||
|
|
||||||
<%-- Included in siteAdmin/main.jsp to handle login/logout form and processing --%>
|
<%-- Included in siteAdmin/main.jsp to handle login/logout form and processing --%>
|
||||||
|
|
||||||
|
<%@ page import="edu.cornell.mannlib.vitro.webapp.controller.login.LoginTemplateHelper" %>
|
||||||
|
<%@ page import="edu.cornell.mannlib.vitro.webapp.controller.VitroRequest" %>
|
||||||
|
|
||||||
<%@ page import="edu.cornell.mannlib.vitro.webapp.beans.Portal" %>
|
|
||||||
<%@ page import="edu.cornell.mannlib.vitro.webapp.controller.Controllers" %>
|
|
||||||
|
|
||||||
<c:url var="loginJSP" value="<%= Controllers.LOGIN_JSP %>" />
|
|
||||||
<c:set var="loginFormTitle" value="<h3>Please log in</h3>" />
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<%
|
|
||||||
int securityLevel = loginHandler.ANYBODY;
|
|
||||||
String loginStatus = loginHandler.getLoginStatus();
|
|
||||||
if ( loginStatus.equals("authenticated")) {
|
|
||||||
%>
|
|
||||||
<div id="logoutPanel">
|
|
||||||
<%
|
<%
|
||||||
} else {
|
String themeDir = new VitroRequest(request).getPortal().getThemeDir().replaceAll("/$", "");
|
||||||
%>
|
%>
|
||||||
<div id="loginPanel" class="pageBodyGroup">
|
|
||||||
<%
|
|
||||||
}
|
|
||||||
if ( loginStatus.equals("authenticated")) {
|
|
||||||
|
|
||||||
// test whether session is still valid
|
|
||||||
String currentSessionId = session.getId();
|
|
||||||
String storedSessionId = loginHandler.getSessionId();
|
|
||||||
|
|
||||||
if ( currentSessionId.equals( storedSessionId ) ) {
|
|
||||||
String currentRemoteAddrStr = request.getRemoteAddr();
|
|
||||||
String storedRemoteAddr = loginHandler.getLoginRemoteAddr();
|
|
||||||
securityLevel = Integer.parseInt( loginHandler.getLoginRole() );
|
|
||||||
|
|
||||||
if ( currentRemoteAddrStr.equals( storedRemoteAddr ) ) {
|
<link rel="stylesheet" type="text/css" href="<%=themeDir%>/css/login.css"/>
|
||||||
%>
|
|
||||||
<form class="logout" name="logout" action="${loginJSP}" method="post">
|
|
||||||
<input type="hidden" name="home" value="<%=portal.getPortalId()%>"/>
|
|
||||||
<em>Logged in as</em> <strong><jsp:getProperty name="loginHandler" property="loginName" /></strong>
|
|
||||||
<input type="submit" name="loginSubmitMode" value="Log out" class="logout-button button" />
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<%
|
|
||||||
} else {
|
|
||||||
%>
|
|
||||||
${loginFormTitle}
|
|
||||||
<em>(IP address has changed)</em><br />
|
|
||||||
<%
|
|
||||||
loginHandler.setLoginStatus("logged out");
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
loginHandler.setLoginStatus("logged out");
|
|
||||||
%>
|
|
||||||
${loginFormTitle}
|
|
||||||
<em>(session has expired)</em><br/>
|
|
||||||
<form class="login" name="login" action="${loginJSP}" method="post" onsubmit="return isValidLogin(this) ">
|
|
||||||
<input type="hidden" name="home" value="<%=portal.getPortalId()%>" />
|
|
||||||
Username: <input type="text" name="loginName" size="10" class="form-item" /><br />
|
|
||||||
Password: <input type="password" name="loginPassword" size="10" class="form-item" /><br />
|
|
||||||
<input type="submit" name="loginSubmitMode" value="Log in" class="form-item button" />
|
|
||||||
</form>
|
|
||||||
<%
|
|
||||||
}
|
|
||||||
|
|
||||||
} else { /* not thrown out by coming from different IP address or expired session; check login status returned by authenticate.java */
|
|
||||||
%>
|
|
||||||
<h3>Please log in</strong></h3>
|
|
||||||
<%
|
|
||||||
if ( loginStatus.equals("logged out")) { %>
|
|
||||||
<em class="noticeText">(currently logged out)</em>
|
|
||||||
<% } else if ( loginStatus.equals("bad_password")) { %>
|
|
||||||
<em class="errorText">(password incorrect)</em><br/>
|
|
||||||
<% } else if ( loginStatus.equals("unknown_username")) { %>
|
|
||||||
<em class="errorText">(unknown username)</em><br/>
|
|
||||||
<% } else if ( loginStatus.equals("first_login_no_password")) { %>
|
|
||||||
<em class="noticeText">(1st login; need to request initial password below)</em>
|
|
||||||
<% } else if ( loginStatus.equals("first_login_mistyped")) { %>
|
|
||||||
<em class="noticeText">(1st login; initial password entered incorrectly)</em>
|
|
||||||
<% } else if ( loginStatus.equals("first_login_changing_password")) { %>
|
|
||||||
<em class="noticeText">(1st login; changing to new private password)</em>
|
|
||||||
<% } else if ( loginStatus.equals("changing_password_repeated_old")) { %>
|
|
||||||
<em class="noticeText">(changing to a different password)</em>
|
|
||||||
<% } else if ( loginStatus.equals("changing_password")) { %>
|
|
||||||
<em class="noticeText">(changing to new password)</em>
|
|
||||||
<% } else if ( loginStatus.equals("none")) { %>
|
|
||||||
<em class="noticeText">(new session)</em><br/>
|
|
||||||
<% } else { %>
|
|
||||||
<em class="errorText">Status unrecognized: <%=loginStatus.replace("_", " ")%></em><br/>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<form class="old-global-form" name="login" action="${loginJSP}" method="post" onsubmit="return isValidLogin(this) ">
|
|
||||||
<input type="hidden" name="home" value="<%=portal.getPortalId()%>" />
|
|
||||||
<label for="loginName">Username:</label>
|
|
||||||
<%
|
|
||||||
if ( loginStatus.equals("bad_password") || loginStatus.equals("first_login_no_password")
|
|
||||||
|| loginStatus.equals("first_login_mistyped") || loginStatus.equals("first_login_changing_password")
|
|
||||||
|| loginStatus.equals("changing_password_repeated_old") || loginStatus.equals("changing_password") ) { %>
|
|
||||||
<input id="username" type="text" name="loginName" value='<%=loginHandler.getLoginName()%>' size="10" class="form-item" /><br />
|
|
||||||
<% } else { %>
|
|
||||||
<input id="username" type="text" name="loginName" size="10" class="form-item" /><br />
|
|
||||||
<% if ( loginStatus.equals("unknown_username") ) { %>
|
|
||||||
<em class="errorText usernameError">Unknown username</em>
|
|
||||||
<% }
|
|
||||||
}
|
|
||||||
%>
|
|
||||||
<label for="loginPassword">Password:</label>
|
|
||||||
<input id="password" type="password" name="loginPassword" size="10" class="form-item" /><br />
|
|
||||||
|
|
||||||
<% String passwordError=loginHandler.getErrorMsg("loginPassword");
|
<%= new LoginTemplateHelper(request).showLoginPage(request) %>
|
||||||
if (passwordError!=null && !passwordError.equals("")) {%>
|
|
||||||
<em class="errorText passwordError"><%=passwordError%></em>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
<input type="submit" name="loginSubmitMode" value="Log in" class="form-item button" />
|
|
||||||
</form>
|
|
||||||
<% } %>
|
|
||||||
|
|
||||||
</div> <!-- end loginPanel -->
|
|
||||||
|
|
|
@ -17,8 +17,14 @@
|
||||||
Portal portal = (Portal) request.getAttribute("portalBean");
|
Portal portal = (Portal) request.getAttribute("portalBean");
|
||||||
final String DEFAULT_SEARCH_METHOD = "fulltext"; /* options are fulltext/termlike */
|
final String DEFAULT_SEARCH_METHOD = "fulltext"; /* options are fulltext/termlike */
|
||||||
|
|
||||||
|
int securityLevel = loginHandler.ANYBODY;
|
||||||
|
String loginStatus = loginHandler.getLoginStatus();
|
||||||
|
if ( loginStatus.equals("authenticated")) {
|
||||||
|
securityLevel = Integer.parseInt( loginHandler.getLoginRole() );
|
||||||
|
}
|
||||||
%>
|
%>
|
||||||
|
|
||||||
|
|
||||||
<div id="content">
|
<div id="content">
|
||||||
|
|
||||||
<div class="tab">
|
<div class="tab">
|
||||||
|
|
|
@ -13,14 +13,10 @@ function isValidLogin( theForm ) {
|
||||||
theForm.loginName.focus();
|
theForm.loginName.focus();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ( isEmptyOrWrongLength( theForm.loginPassword.value)) {
|
if ( isEmptyPassword( theForm.loginPassword.value)) {
|
||||||
theForm.loginPassword.focus();
|
theForm.loginPassword.focus();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//alert("theForm.loginPassword.value=" + theForm.loginPassword.value );
|
|
||||||
theForm.loginPassword.value = calcMD5( theForm.loginPassword.value );
|
|
||||||
//alert("theForm.loginPassword.value=" + theForm.loginPassword.value );
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,15 +28,39 @@ function isEmpty( aStr ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isEmptyOrWrongLength( aStr ) {
|
function isEmptyPassword( aStr ) {
|
||||||
if ( aStr.length == 0 ) {
|
if ( aStr.length == 0 ) {
|
||||||
alert("Please enter a password to log in");
|
alert("Please enter a password to log in");
|
||||||
return true;
|
return true;
|
||||||
} else if ( aStr.length < <%=User.MIN_PASSWORD_LENGTH%> || aStr.length > <%=User.MAX_PASSWORD_LENGTH%>) {
|
|
||||||
alert("Please enter a password between 6 and 12 characters long");
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isReasonableNewPassword( theForm ) {
|
||||||
|
if ( isWrongLengthPassword( theForm.newPassword.value)) {
|
||||||
|
theForm.newPassword.focus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ( isMismatchedPasswords( theForm.newPassword.value, theForm.confirmPassword.value)) {
|
||||||
|
theForm.newPassword.focus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isWrongLengthPassword( aStr ) {
|
||||||
|
if ( aStr.length < <%=User.MIN_PASSWORD_LENGTH%> || aStr.length > <%=User.MAX_PASSWORD_LENGTH%>) {
|
||||||
|
alert("Please enter a password between <%=User.MIN_PASSWORD_LENGTH%> and <%=User.MAX_PASSWORD_LENGTH%> characters long");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isMismatchedPasswords( one, two ) {
|
||||||
|
if ( one != two ) {
|
||||||
|
alert("Passwords do not match");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Give initial focus to the password or username field
|
//Give initial focus to the password or username field
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
<tr class="editformcell">
|
<tr class="editformcell">
|
||||||
<td valign="bottom" colspan="2">
|
<td valign="bottom" colspan="2">
|
||||||
<b>User Name*</b><br/>
|
<b>Email address*</b><br/>
|
||||||
<input type="text" name="Username" value="${formValue['Username']}" size="60" maxlength="120" />
|
<input type="text" name="Username" value="${formValue['Username']}" size="60" maxlength="120" />
|
||||||
<span class="warning"><form:error name="Username"/></span>
|
<span class="warning"><form:error name="Username"/></span>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||||
|
|
||||||
|
<#-- Crop the replacement main image for an Individual, to produce a thumbnail. -->
|
||||||
|
|
||||||
|
<h2>Forced password change</h2>
|
||||||
|
|
||||||
|
${stylesheets.addFromTheme("/login.css")}
|
||||||
|
|
||||||
|
<div id="formLogin" class="pageBodyGroup">
|
||||||
|
<h2>Create Your New Password</h2>
|
||||||
|
|
||||||
|
<#if errorMessage??>
|
||||||
|
<div id="errorAlert"><img src="${alertImageUrl}" width="32" height="31" alert="Error alert icon"/>
|
||||||
|
<p>${errorMessage}</p>
|
||||||
|
</div>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<form action="${formAction}" method="post" onsubmit="return isReasonableNewPassword(this)">
|
||||||
|
<label for="newPassword">Password</label>
|
||||||
|
<input type="password" name="newPassword" />
|
||||||
|
<label for="confirmPassword">Confirm Password</label>
|
||||||
|
<input type="password" name="confirmPassword" />
|
||||||
|
<br />
|
||||||
|
<input name="passwordChangeForm" type="submit" class="submit" value="Save Changes"/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
29
webapp/web/templates/freemarker/body/login/login.ftl
Normal file
29
webapp/web/templates/freemarker/body/login/login.ftl
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
|
||||||
|
|
||||||
|
<#-- Crop the replacement main image for an Individual, to produce a thumbnail. -->
|
||||||
|
|
||||||
|
${stylesheets.addFromTheme("/login.css")}
|
||||||
|
|
||||||
|
<div id="formLogin" class="pageBodyGroup">
|
||||||
|
<h2>Log in</h2>
|
||||||
|
|
||||||
|
<#if infoMessage??>
|
||||||
|
<h3>${infoMessage}</h3>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<#if errorMessage??>
|
||||||
|
<div id="errorAlert"><img src="${alertImageUrl}" width="32" height="31" alert="Error alert icon"/>
|
||||||
|
<p>${errorMessage}</p>
|
||||||
|
</div>
|
||||||
|
</#if>
|
||||||
|
|
||||||
|
<form action="${formAction}" method="post" onsubmit="return isValidLogin(this)">
|
||||||
|
<label for="loginName">Email</label>
|
||||||
|
<input name="loginName" type="text" value="${loginName}" />
|
||||||
|
<label for="loginPassword">Password</label>
|
||||||
|
<input type="password" name="loginPassword" />
|
||||||
|
<br />
|
||||||
|
<input name="loginForm" type="submit" class="submit" value="Log in"/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
Loading…
Add table
Reference in a new issue