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;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
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.List;
|
||||
import java.util.Map;
|
||||
|
@ -13,6 +17,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.apache.commons.logging.Log;
|
||||
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.beans.User;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.Controllers;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
|
||||
import edu.cornell.mannlib.vitro.webapp.controller.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.WebappDaoFactory;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.LoginEvent;
|
||||
import edu.cornell.mannlib.vitro.webapp.dao.jena.LoginLogoutEvent;
|
||||
|
||||
public class Authenticate extends VitroHttpServlet {
|
||||
private static final int DEFAULT_PORTAL_ID=1;
|
||||
public static final String USER_SESSION_MAP_ATTR = "userURISessionMap";
|
||||
private UserDao userDao = null;
|
||||
private static final Log log = LogFactory.getLog(Authenticate.class.getName());
|
||||
public class Authenticate extends FreeMarkerHttpServlet {
|
||||
private static final Log log = LogFactory.getLog(Authenticate.class
|
||||
.getName());
|
||||
|
||||
public void doPost( HttpServletRequest request, HttpServletResponse response ) {
|
||||
try {
|
||||
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" );
|
||||
/** The username field on the login form. */
|
||||
private static final String PARAMETER_USERNAME = "loginName";
|
||||
|
||||
//obtain a db connection and perform a db query
|
||||
//ensuring that the username exists
|
||||
/** The password field on the login form. */
|
||||
private static final String PARAMETER_PASSWORD = "loginPassword";
|
||||
|
||||
// JCR 20040905 passing on portal home parameter
|
||||
String portalIdStr=(portalIdStr=request.getParameter("home"))==null?String.valueOf(DEFAULT_PORTAL_ID):portalIdStr;
|
||||
//request.setAttribute("home",portalIdStr);
|
||||
/** The new password field on the password change form. */
|
||||
private static final String PARAMETER_NEW_PASSWORD = "newPassword";
|
||||
|
||||
// Build the redirect URLs
|
||||
String contextPath = request.getContextPath();
|
||||
String urlParams = "?home=" + portalIdStr + "&login=block";
|
||||
String loginUrl = contextPath + Controllers.LOGIN + urlParams;
|
||||
String siteAdminUrl = contextPath + Controllers.SITE_ADMIN + urlParams;
|
||||
/** The confirm password field on the password change form. */
|
||||
private static final String PARAMETER_CONFIRM_PASSWORD = "confirmPassword";
|
||||
|
||||
if (userDao==null) {
|
||||
f.setErrorMsg("loginPassword","unable to get UserDao");
|
||||
f.setLoginStatus("no UserDao");
|
||||
response.sendRedirect(loginUrl);
|
||||
return;
|
||||
}
|
||||
/** If they are logging in, show them this form. */
|
||||
public static final String TEMPLATE_LOGIN = "login/login.ftl";
|
||||
|
||||
/* used for encoding cleartext passwords sent via http before store in database
|
||||
String loginPassword = "";
|
||||
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;
|
||||
}
|
||||
/** If they are changing their password on first login, show them this form. */
|
||||
public static final String TEMPLATE_FORCE_PASSWORD_CHANGE = "login/forcedPasswordChange.ftl";
|
||||
|
||||
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) {
|
||||
f.setErrorMsg( "loginName","No user found with username " + f.getLoginName() );
|
||||
f.setLoginStatus("unknown_username");
|
||||
response.sendRedirect(loginUrl);
|
||||
return;
|
||||
}
|
||||
/** If no portal is specified in the request, use this one. */
|
||||
private static final int DEFAULT_PORTAL_ID = 1;
|
||||
|
||||
// logic for authentication
|
||||
// first check for new users (loginCount==0)
|
||||
// 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;
|
||||
}
|
||||
/** Where do we find the User/Session map in the servlet context? */
|
||||
public static final String USER_SESSION_MAP_ATTR = "userURISessionMap";
|
||||
|
||||
//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());
|
||||
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", "" );
|
||||
User user = null;
|
||||
|
||||
//System.out.println("updating loginCount and modTime");
|
||||
|
||||
Map<String,HttpSession> userURISessionMap = getUserURISessionMapFromContext( getServletContext() );
|
||||
userURISessionMap.put( user.getURI(), request.getSession() );
|
||||
|
||||
sendLoginNotifyEvent(new LoginEvent( user.getURI() ), getServletContext(), session);
|
||||
|
||||
user.setLoginCount(user.getLoginCount()+1);
|
||||
userDao.updateUser(user);
|
||||
try {
|
||||
// Process any input from the login form.
|
||||
State entryState = getCurrentLoginState(vreq);
|
||||
log.debug("State on entry: " + entryState);
|
||||
|
||||
if ( user.getLoginCount() == 2 ) { // first login
|
||||
Calendar cal = Calendar.getInstance();
|
||||
user.setFirstTime(cal.getTime());
|
||||
userDao.updateUser(user);
|
||||
}
|
||||
switch (entryState) {
|
||||
case LOGGING_IN:
|
||||
user = checkLoginProgress(vreq);
|
||||
if (user != null) {
|
||||
whatNextForThisGuy(vreq, user);
|
||||
}
|
||||
break;
|
||||
case FORCED_PASSWORD_CHANGE:
|
||||
user = checkChangeProgress(vreq);
|
||||
if (user != null) {
|
||||
recordSuccessfulPasswordChange(vreq, user);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
*If you set a postLoginRequest attribute in the session and forward to about
|
||||
*then this will attempt to send the client back to the original page after the login.
|
||||
*/
|
||||
String forwardStr = (String) request.getSession().getAttribute("postLoginRequest");
|
||||
request.getSession().removeAttribute("postLoginRequest");
|
||||
if (forwardStr == null) {
|
||||
String contextPostLoginRequest = (String) getServletContext().getAttribute("postLoginRequest");
|
||||
if (contextPostLoginRequest != null) {
|
||||
forwardStr = (contextPostLoginRequest.indexOf(":") == -1)
|
||||
? request.getContextPath() + contextPostLoginRequest
|
||||
: contextPostLoginRequest;
|
||||
}
|
||||
}
|
||||
|
||||
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 ){
|
||||
forwardStr = request.getContextPath() + "/individual?uri=" + URLEncoder.encode(uris.get(0), "UTF-8");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (forwardStr != null) {
|
||||
response.sendRedirect(forwardStr);
|
||||
} else {
|
||||
response.sendRedirect(siteAdminUrl);
|
||||
//RequestDispatcher rd = getServletContext().getRequestDispatcher(url);
|
||||
//rd.forward(request,response);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
log.error( t.getMessage() );
|
||||
t.printStackTrace();
|
||||
}
|
||||
}
|
||||
// Figure out where they should be, and redirect.
|
||||
State exitState = getCurrentLoginState(vreq);
|
||||
log.debug("State on exit: " + exitState);
|
||||
|
||||
switch (exitState) {
|
||||
case LOGGED_IN:
|
||||
redirectLoggedInUser(vreq, response);
|
||||
break;
|
||||
default:
|
||||
showLoginScreen(vreq, response);
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
showSystemError(e, response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* They are logging in. Are they successful?
|
||||
*/
|
||||
private User checkLoginProgress(HttpServletRequest request) {
|
||||
String username = request.getParameter(PARAMETER_USERNAME);
|
||||
String password = request.getParameter(PARAMETER_PASSWORD);
|
||||
|
||||
LoginProcessBean bean = getLoginProcessBean(request);
|
||||
bean.clearMessage();
|
||||
log.trace("username=" + username + ", password=" + password + ", bean="
|
||||
+ bean);
|
||||
|
||||
if ((username == null) || username.isEmpty()) {
|
||||
bean.setMessage(Message.NO_USERNAME);
|
||||
return null;
|
||||
} else {
|
||||
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();
|
||||
results.add("User");
|
||||
results.add("Email address");
|
||||
results.add("first name");
|
||||
results.add("last name");
|
||||
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 --%>
|
||||
|
||||
<%@ 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 ) ) {
|
||||
%>
|
||||
<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 />
|
||||
<link rel="stylesheet" type="text/css" href="<%=themeDir%>/css/login.css"/>
|
||||
|
||||
<% String passwordError=loginHandler.getErrorMsg("loginPassword");
|
||||
if (passwordError!=null && !passwordError.equals("")) {%>
|
||||
<em class="errorText passwordError"><%=passwordError%></em>
|
||||
<% } %>
|
||||
<%= new LoginTemplateHelper(request).showLoginPage(request) %>
|
||||
|
||||
<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");
|
||||
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 class="tab">
|
||||
|
|
|
@ -13,14 +13,10 @@ function isValidLogin( theForm ) {
|
|||
theForm.loginName.focus();
|
||||
return false;
|
||||
}
|
||||
if ( isEmptyOrWrongLength( theForm.loginPassword.value)) {
|
||||
if ( isEmptyPassword( theForm.loginPassword.value)) {
|
||||
theForm.loginPassword.focus();
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -32,15 +28,39 @@ function isEmpty( aStr ) {
|
|||
return false;
|
||||
}
|
||||
|
||||
function isEmptyOrWrongLength( aStr ) {
|
||||
function isEmptyPassword( aStr ) {
|
||||
if ( aStr.length == 0 ) {
|
||||
alert("Please enter a password to log in");
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
<tr class="editformcell">
|
||||
<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" />
|
||||
<span class="warning"><form:error name="Username"/></span>
|
||||
</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