NIHVIVO-1460 implement the ProgramLogin servlet.

This commit is contained in:
jeb228 2010-12-09 17:18:27 +00:00
parent 192b722de3
commit 3b3111be82
3 changed files with 336 additions and 0 deletions

View file

@ -1097,6 +1097,15 @@
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.authenticate.LoginExternalAuthReturn</servlet-class>
</servlet>
<servlet>
<servlet-name>programLogin</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.authenticate.ProgramLogin</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>programLogin</servlet-name>
<url-pattern>/programLogin</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>logout</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.edit.Logout</servlet-class>

View file

@ -0,0 +1,116 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.authenticate;
import static edu.cornell.mannlib.vedit.beans.LoginStatusBean.AuthenticationSource.INTERNAL;
import static edu.cornell.mannlib.vitro.webapp.beans.User.MAX_PASSWORD_LENGTH;
import static edu.cornell.mannlib.vitro.webapp.beans.User.MIN_PASSWORD_LENGTH;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import edu.cornell.mannlib.vitro.webapp.beans.User;
/**
* Provide a means for programmatic login If they provide the right parameters,
* log them in and send 200. Otherwise, send 403 error.
*/
public class ProgramLogin extends HttpServlet {
public static final String PARAM_USERNAME = "username";
public static final String PARAM_PASSWORD = "password";
public static final String PARAM_NEW_PASSWORD = "newPassword";
public static final int ERROR_CODE = 403;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
Authenticator auth = Authenticator.getInstance(req);
String username = req.getParameter(PARAM_USERNAME);
String password = req.getParameter(PARAM_PASSWORD);
String newPassword = req.getParameter(PARAM_NEW_PASSWORD);
// username is required
if ((username == null) || username.isEmpty()) {
resp.sendError(ERROR_CODE, PARAM_USERNAME
+ " parameter is required.");
return;
}
// password is required
if ((password == null) || password.isEmpty()) {
resp.sendError(ERROR_CODE, PARAM_PASSWORD
+ " parameter is required.");
return;
}
// user must exist and password must be correct
if (!auth.isExistingUser(username)
|| (!auth.isCurrentPassword(username, password))) {
resp.sendError(ERROR_CODE, PARAM_USERNAME + " or " + PARAM_PASSWORD
+ " is incorrect.");
return;
}
User user = auth.getUserByUsername(username);
boolean firstTime = (user.getLoginCount() == 0);
if (firstTime) {
// on first-time login, new password is required
if ((newPassword == null) || newPassword.isEmpty()) {
resp.sendError(ERROR_CODE, "first-time login: "
+ PARAM_NEW_PASSWORD + " parameter is required.");
return;
}
// on first-time login, new password must be correct length
if ((newPassword.length() < MIN_PASSWORD_LENGTH)
|| (newPassword.length() > MAX_PASSWORD_LENGTH)) {
resp.sendError(ERROR_CODE, PARAM_PASSWORD + " must be between "
+ MIN_PASSWORD_LENGTH + " and " + MAX_PASSWORD_LENGTH
+ " characters.");
return;
}
// on first-time login, new password must be different from old
if (auth.isCurrentPassword(username, newPassword)) {
resp.sendError(ERROR_CODE, PARAM_NEW_PASSWORD
+ " must not be the same as " + PARAM_PASSWORD);
return;
}
auth.recordNewPassword(username, newPassword);
auth.recordLoginAgainstUserAccount(username, INTERNAL);
sendSuccess(resp, "first-time login successful.");
return;
} else {
// not first-time login, new password is not allowed
if ((newPassword != null) && (!newPassword.isEmpty())) {
resp.sendError(ERROR_CODE, "not first-time login: "
+ PARAM_NEW_PASSWORD + " parameter is not allowed.");
return;
}
auth.recordLoginAgainstUserAccount(username, INTERNAL);
sendSuccess(resp, "login successful.");
return;
}
}
private void sendSuccess(HttpServletResponse resp, String message)
throws IOException {
PrintWriter writer = resp.getWriter();
writer.println(message);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
doGet(req, resp);
}
}

View file

@ -0,0 +1,211 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.authenticate;
import static edu.cornell.mannlib.vitro.webapp.controller.authenticate.ProgramLogin.PARAM_NEW_PASSWORD;
import static edu.cornell.mannlib.vitro.webapp.controller.authenticate.ProgramLogin.PARAM_PASSWORD;
import static edu.cornell.mannlib.vitro.webapp.controller.authenticate.ProgramLogin.PARAM_USERNAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.net.URL;
import java.util.Date;
import javax.servlet.ServletException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.log4j.Level;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import stubs.javax.servlet.ServletConfigStub;
import stubs.javax.servlet.ServletContextStub;
import stubs.javax.servlet.http.HttpServletRequestStub;
import stubs.javax.servlet.http.HttpServletResponseStub;
import stubs.javax.servlet.http.HttpSessionStub;
import edu.cornell.mannlib.vedit.beans.LoginStatusBean;
import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
import edu.cornell.mannlib.vitro.webapp.beans.User;
import edu.cornell.mannlib.vitro.webapp.controller.edit.Authenticate;
/**
* Test the basic features of ProgramTest.
*/
public class ProgramLoginTest extends AbstractTestClass {
private static final Log log = LogFactory.getLog(ProgramLoginTest.class);
private static final String NEW_USER_URI = "new_user_uri";
private static final String NEW_USER_NAME = "new_user";
private static final String NEW_USER_PASSWORD = "new_user_pw";
private static final User NEW_USER = createUser(NEW_USER_URI,
NEW_USER_NAME, NEW_USER_PASSWORD, 0);
private static final String OLD_USER_URI = "old_user_uri";
private static final String OLD_USER_NAME = "old_user";
private static final String OLD_USER_PASSWORD = "old_user_pw";
private static final User OLD_USER = createUser(OLD_USER_URI,
OLD_USER_NAME, OLD_USER_PASSWORD, 10);
private AuthenticatorStub authenticator;
private ServletContextStub servletContext;
private ServletConfigStub servletConfig;
private HttpSessionStub session;
private HttpServletRequestStub request;
private HttpServletResponseStub response;
private ProgramLogin servlet;
@Before
public void setLogging() {
setLoggerLevel(this.getClass(), Level.DEBUG);
}
@Before
public void setup() throws Exception {
authenticator = AuthenticatorStub.setup();
authenticator.addUser(NEW_USER);
authenticator.addUser(OLD_USER);
servletContext = new ServletContextStub();
servletConfig = new ServletConfigStub();
servletConfig.setServletContext(servletContext);
servlet = new ProgramLogin();
servlet.init(servletConfig);
session = new HttpSessionStub();
session.setServletContext(servletContext);
request = new HttpServletRequestStub();
request.setSession(session);
request.setRequestUrl(new URL("http://this.that/vivo/programLogin"));
request.setMethod("GET");
response = new HttpServletResponseStub();
}
private static User createUser(String uri, String name, String password,
int loginCount) {
User user = new User();
user.setUsername(name);
user.setURI(uri);
user.setRoleURI(String.valueOf(50));
user.setMd5password(Authenticate.applyMd5Encoding(password));
user.setLoginCount(loginCount);
if (loginCount > 0) {
user.setFirstTime(new Date(0));
}
return user;
}
@After
public void cleanup() {
if (servlet != null) {
servlet.destroy();
}
}
@Test
public void noUsername() {
executeRequest(null, null, null);
assert403();
}
@Test
public void noPassword() {
executeRequest(OLD_USER_NAME, null, null);
assert403();
}
@Test
public void unrecognizedUser() {
executeRequest("bogusUsername", "bogusPassword", null);
assert403();
}
@Test
public void wrongPassword() {
executeRequest(OLD_USER_NAME, "bogusPassword", null);
assert403();
}
@Test
public void success() {
executeRequest(OLD_USER_NAME, OLD_USER_PASSWORD, null);
assertSuccess();
}
@Test
public void newPasswordNotNeeded() {
executeRequest(OLD_USER_NAME, OLD_USER_PASSWORD, "unneededPW");
assert403();
}
@Test
public void newPasswordMissing() {
executeRequest(NEW_USER_NAME, NEW_USER_PASSWORD, null);
assert403();
}
@Test
public void newPasswordTooLong() {
executeRequest(NEW_USER_NAME, NEW_USER_PASSWORD, "reallyLongPassword");
assert403();
}
@Test
public void newPasswordEqualsOldPassword() {
executeRequest(NEW_USER_NAME, NEW_USER_PASSWORD, NEW_USER_PASSWORD);
assert403();
}
@Test
public void successWithNewPassword() {
executeRequest(NEW_USER_NAME, NEW_USER_PASSWORD, "newerBetter");
assertSuccess();
}
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
private void executeRequest(String username, String password,
String newPassword) {
if (username != null) {
request.addParameter(PARAM_USERNAME, username);
}
if (password != null) {
request.addParameter(PARAM_PASSWORD, password);
}
if (newPassword != null) {
request.addParameter(PARAM_NEW_PASSWORD, newPassword);
}
try {
servlet.doGet(request, response);
} catch (ServletException e) {
log.error(e, e);
fail(e.toString());
} catch (IOException e) {
log.error(e, e);
fail(e.toString());
}
}
private void assert403() {
assertEquals("status", 403, response.getStatus());
log.debug("Message was '" + response.getErrorMessage() + "'");
assertEquals("logged in", false, LoginStatusBean.getBean(session)
.isLoggedIn());
}
private void assertSuccess() {
assertEquals("status", 200, response.getStatus());
assertEquals("logged in", true, LoginStatusBean.getBean(session)
.isLoggedIn());
}
}