NIHVIVO-2279 Implement CreatePassword - start to separate into user vs. admin functions.

This commit is contained in:
j2blake 2011-05-25 20:03:02 +00:00
parent a220c5cba6
commit 1bac5c5fbc
18 changed files with 538 additions and 45 deletions

View file

@ -766,12 +766,21 @@
</servlet-mapping> </servlet-mapping>
<servlet> <servlet>
<servlet-name>UserAccounts</servlet-name> <servlet-name>AccountsAdmin</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsController</servlet-class> <servlet-class>edu.cornell.mannlib.vitro.webapp.controller.accounts.admin.UserAccountsAdminController</servlet-class>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>UserAccounts</servlet-name> <servlet-name>AccountsAdmin</servlet-name>
<url-pattern>/userAccounts/*</url-pattern> <url-pattern>/accountsAdmin/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>AccountsUser</servlet-name>
<servlet-class>edu.cornell.mannlib.vitro.webapp.controller.accounts.user.UserAccountsUserController</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AccountsUser</servlet-name>
<url-pattern>/accounts/*</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet> <servlet>

View file

@ -11,11 +11,17 @@ import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator;
/** /**
* Information about the account of a user. URI, email, password, etc. * Information about the account of a user. URI, email, password, etc.
*
* The "password link expires hash" is just a string that is derived from the
* value in the passwordLinkExpires field. It doesn't have to be a hash, and
* there is no need for it to be cryptographic, but it seems embarrassing to
* just send the value as a clear string. There is no real need for security
* here, except that a brute force attack would allow someone to change the
* password on an account that they know has a password change pending.
*/ */
public class UserAccount { public class UserAccount {
public static final int MIN_PASSWORD_LENGTH = 6;
public final static int MIN_PASSWORD_LENGTH = 6; public static final int MAX_PASSWORD_LENGTH = 12;
public final static int MAX_PASSWORD_LENGTH = 12;
public enum Status { public enum Status {
ACTIVE, INACTIVE; ACTIVE, INACTIVE;
@ -110,8 +116,8 @@ public class UserAccount {
} }
public String getPasswordLinkExpiresHash() { public String getPasswordLinkExpiresHash() {
return Authenticator.applyMd5Encoding(String return limitStringLength(8, Authenticator.applyMd5Encoding(String
.valueOf(passwordLinkExpires)); .valueOf(passwordLinkExpires)));
} }
public void setPasswordLinkExpires(long passwordLinkExpires) { public void setPasswordLinkExpires(long passwordLinkExpires) {
@ -170,6 +176,16 @@ public class UserAccount {
return (value == null) ? defaultValue : value; return (value == null) ? defaultValue : value;
} }
private String limitStringLength(int limit, String s) {
if (s == null) {
return "";
} else if (s.length() <= limit) {
return s;
} else {
return s.substring(0, limit);
}
}
@Override @Override
public String toString() { public String toString() {
return "UserAccount[uri=" + uri + (", emailAddress=" + emailAddress) return "UserAccount[uri=" + uri + (", emailAddress=" + emailAddress)

View file

@ -6,12 +6,14 @@ import static javax.mail.Message.RecipientType.TO;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount.Status; import edu.cornell.mannlib.vitro.webapp.beans.UserAccount.Status;
import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory; import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory;
import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailMessage; import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailMessage;
@ -52,7 +54,8 @@ public abstract class UserAccountsAddPageStrategy {
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
private static class EmailStrategy extends UserAccountsAddPageStrategy { private static class EmailStrategy extends UserAccountsAddPageStrategy {
public static final String CREATE_PASSWORD_URL = "/userAccounts/createPassword"; public static final String CREATE_PASSWORD_URL = "/accounts/createPassword";
private static final int DAYS_TO_ACTIVATE_ACCOUNT = 90;
private boolean sentEmail; private boolean sentEmail;
@ -73,10 +76,16 @@ public abstract class UserAccountsAddPageStrategy {
@Override @Override
protected void setAdditionalProperties(UserAccount u) { protected void setAdditionalProperties(UserAccount u) {
u.setPasswordLinkExpires(new Date().getTime()); u.setPasswordLinkExpires(figureExpirationDate().getTime());
u.setStatus(Status.INACTIVE); u.setStatus(Status.INACTIVE);
} }
private Date figureExpirationDate() {
Calendar c = Calendar.getInstance();
c.add(Calendar.DATE, DAYS_TO_ACTIVATE_ACCOUNT);
return c.getTime();
}
@Override @Override
protected void addMoreBodyValues(Map<String, Object> body) { protected void addMoreBodyValues(Map<String, Object> body) {
body.put("emailIsEnabled", Boolean.TRUE); body.put("emailIsEnabled", Boolean.TRUE);
@ -93,8 +102,8 @@ public abstract class UserAccountsAddPageStrategy {
.createNewMessage(page.vreq); .createNewMessage(page.vreq);
email.addRecipient(TO, page.getAddedAccount().getEmailAddress()); email.addRecipient(TO, page.getAddedAccount().getEmailAddress());
email.setSubject("Your VIVO account has been created."); email.setSubject("Your VIVO account has been created.");
email.setHtmlTemplate("userAccounts-createdEmail-html.ftl"); email.setHtmlTemplate("userAccounts-acctCreatedEmail-html.ftl");
email.setTextTemplate("userAccounts-createdEmail-text.ftl"); email.setTextTemplate("userAccounts-acctCreatedEmail-text.ftl");
email.setBodyMap(body); email.setBodyMap(body);
email.send(); email.send();
@ -103,11 +112,11 @@ public abstract class UserAccountsAddPageStrategy {
private String buildCreatePasswordLink() { private String buildCreatePasswordLink() {
try { try {
String uri = page.getAddedAccount().getUri(); String email = page.getAddedAccount().getEmailAddress();
String hash = page.getAddedAccount() String hash = page.getAddedAccount()
.getPasswordLinkExpiresHash(); .getPasswordLinkExpiresHash();
String relativeUrl = UrlBuilder.getUrl(CREATE_PASSWORD_URL, "user", String relativeUrl = UrlBuilder.getUrl(CREATE_PASSWORD_URL, "user",
uri, "key", hash); email, "key", hash);
URL context = new URL(page.vreq.getRequestURL().toString()); URL context = new URL(page.vreq.getRequestURL().toString());
URL url = new URL(context, relativeUrl); URL url = new URL(context, relativeUrl);

View file

@ -9,8 +9,10 @@ import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.ManageUserAccounts; import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.ManageUserAccounts;
import edu.cornell.mannlib.vitro.webapp.beans.DisplayMessage;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.RedirectResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
/** /**
@ -23,6 +25,7 @@ public class UserAccountsController extends FreemarkerHttpServlet {
private static final String ACTION_ADD = "/add"; private static final String ACTION_ADD = "/add";
private static final String ACTION_DELETE = "/delete"; private static final String ACTION_DELETE = "/delete";
private static final String ACTION_EDIT = "/edit"; private static final String ACTION_EDIT = "/edit";
private static final String ACTION_CREATE_PASSWORD = "/createPassword";
@Override @Override
protected Actions requiredActions(VitroRequest vreq) { protected Actions requiredActions(VitroRequest vreq) {
@ -44,6 +47,8 @@ public class UserAccountsController extends FreemarkerHttpServlet {
return handleEditRequest(vreq); return handleEditRequest(vreq);
} else if (ACTION_DELETE.equals(action)) { } else if (ACTION_DELETE.equals(action)) {
return handleDeleteRequest(vreq); return handleDeleteRequest(vreq);
} else if (ACTION_CREATE_PASSWORD.equals(action)) {
return handleCreatePasswordRequest(vreq);
} else { } else {
return handleListRequest(vreq); return handleListRequest(vreq);
} }
@ -64,7 +69,6 @@ public class UserAccountsController extends FreemarkerHttpServlet {
private ResponseValues handleEditRequest(VitroRequest vreq) { private ResponseValues handleEditRequest(VitroRequest vreq) {
UserAccountsEditPage page = new UserAccountsEditPage(vreq); UserAccountsEditPage page = new UserAccountsEditPage(vreq);
page.parseParametersAndValidate();
if (page.isSubmit() && page.isValid()) { if (page.isSubmit() && page.isValid()) {
page.updateAccount(); page.updateAccount();
UserAccountsListPage listPage = new UserAccountsListPage(vreq); UserAccountsListPage listPage = new UserAccountsListPage(vreq);
@ -83,8 +87,30 @@ public class UserAccountsController extends FreemarkerHttpServlet {
.showPageWithDeletions(deletedUris); .showPageWithDeletions(deletedUris);
} }
private ResponseValues handleCreatePasswordRequest(VitroRequest vreq) {
UserAccountsCreatePasswordPage page = new UserAccountsCreatePasswordPage(
vreq);
if (page.isBogus()) {
return showHomePage(vreq,
"Request failed. Please contact your system administrator.");
} else if (page.isSubmit() && page.isValid()) {
page.createPassword();
return showHomePage(vreq,
"Your password has been saved. Please log in.");
} else {
return page.showPage();
}
}
private ResponseValues handleListRequest(VitroRequest vreq) { private ResponseValues handleListRequest(VitroRequest vreq) {
UserAccountsListPage page = new UserAccountsListPage(vreq); UserAccountsListPage page = new UserAccountsListPage(vreq);
return page.showPage(); return page.showPage();
} }
private ResponseValues showHomePage(VitroRequest vreq, String message) {
DisplayMessage.setMessage(vreq, message);
return new RedirectResponseValues("/");
}
} }

View file

@ -0,0 +1,165 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.accounts;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
import edu.cornell.mannlib.vitro.webapp.beans.UserAccount.Status;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.accounts.user.UserAccountsUserController;
import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
/**
* TODO
*/
public class UserAccountsCreatePasswordPage extends UserAccountsPage {
private static final Log log = LogFactory
.getLog(UserAccountsCreatePasswordPage.class);
private static final String PARAMETER_SUBMIT = "submitCreatePassword";
private static final String PARAMETER_USER = "user";
private static final String PARAMETER_KEY = "key";
private static final String PARAMETER_PASSWORD = "password";
private static final String PARAMETER_CONFIRM_PASSWORD = "confirmPassword";
private static final String TEMPLATE_NAME = "userAccounts-createPassword.ftl";
private static final String ERROR_NO_PASSWORD = "errorPasswordIsEmpty";
private static final String ERROR_WRONG_PASSWORD_LENGTH = "errorPasswordIsWrongLength";
private static final String ERROR_PASSWORDS_DONT_MATCH = "errorPasswordsDontMatch";
private boolean submit;
private String userEmail = "";
private String key = "";
private String password = "";
private String confirmPassword = "";
private UserAccount userAccount;
/** The result of checking whether this request is even appropriate. */
private String bogusMessage = "";
/** The result of validating a "submit" request. */
private String errorCode = "";
public UserAccountsCreatePasswordPage(VitroRequest vreq) {
super(vreq);
parseRequestParameters();
validateUserAccountInfo();
if (isSubmit() && !isBogus()) {
validateParameters();
}
}
private void parseRequestParameters() {
submit = isFlagOnRequest(PARAMETER_SUBMIT);
userEmail = getStringParameter(PARAMETER_USER, "");
key = getStringParameter(PARAMETER_KEY, "");
password = getStringParameter(PARAMETER_PASSWORD, "");
confirmPassword = getStringParameter(PARAMETER_CONFIRM_PASSWORD, "");
}
private void validateUserAccountInfo() {
userAccount = userAccountsDao.getUserAccountByEmail(userEmail);
if (userAccount == null) {
log.warn("Create password for '" + userEmail
+ "' is bogus: no such user");
bogusMessage = UserAccountsUserController.BOGUS_STANDARD_MESSAGE;
return;
}
if (userAccount.getPasswordLinkExpires() == 0L) {
log.warn("Create password for '" + userEmail
+ "' is bogus: password change is not pending.");
bogusMessage = "The account for " + userEmail
+ " has already been activated.";
return;
}
Date expirationDate = new Date(userAccount.getPasswordLinkExpires());
if (expirationDate.before(new Date())) {
log.warn("Create password for '" + userEmail
+ "' is bogus: expiration date has passed.");
bogusMessage = UserAccountsUserController.BOGUS_STANDARD_MESSAGE;
return;
}
String expectedKey = userAccount.getPasswordLinkExpiresHash();
if (!key.equals(expectedKey)) {
log.warn("Create password for '" + userEmail + "' is bogus: key ("
+ key + ") doesn't match expected key (" + expectedKey
+ ")");
bogusMessage = UserAccountsUserController.BOGUS_STANDARD_MESSAGE;
return;
}
}
private void validateParameters() {
if (password.isEmpty()) {
errorCode = ERROR_NO_PASSWORD;
} else if (!checkPasswordLength(password)) {
errorCode = ERROR_WRONG_PASSWORD_LENGTH;
} else if (!password.equals(confirmPassword)) {
errorCode = ERROR_PASSWORDS_DONT_MATCH;
}
}
private boolean checkPasswordLength(String pw) {
return pw.length() >= UserAccount.MIN_PASSWORD_LENGTH
&& pw.length() <= UserAccount.MAX_PASSWORD_LENGTH;
}
public boolean isBogus() {
return bogusMessage.isEmpty();
}
public String getBogusMessage() {
return bogusMessage;
}
public boolean isSubmit() {
return submit;
}
public boolean isValid() {
return errorCode.isEmpty();
}
public void createPassword() {
userAccount.setMd5Password(Authenticator.applyMd5Encoding(password));
userAccount.setPasswordLinkExpires(0L);
userAccount.setStatus(Status.ACTIVE);
userAccountsDao.updateUserAccount(userAccount);
log.debug("Set password on '" + userAccount.getEmailAddress()
+ "' to '" + password + "'");
}
public final ResponseValues showPage() {
Map<String, Object> body = new HashMap<String, Object>();
body.put("minimumLength", UserAccount.MIN_PASSWORD_LENGTH);
body.put("maximumLength", UserAccount.MAX_PASSWORD_LENGTH);
body.put("userAccount", userAccount);
body.put("key", userAccount.getPasswordLinkExpiresHash());
body.put("password", password);
body.put("confirmPassword", confirmPassword);
body.put("formUrls", buildUrlsMap());
if (!errorCode.isEmpty()) {
body.put(errorCode, Boolean.TRUE);
}
return new TemplateResponseValues(TEMPLATE_NAME, body);
}
}

View file

@ -21,7 +21,7 @@ public class UserAccountsDeleter extends UserAccountsPage {
/** Might be empty, but never null. */ /** Might be empty, but never null. */
private final String[] uris; private final String[] uris;
protected UserAccountsDeleter(VitroRequest vreq) { public UserAccountsDeleter(VitroRequest vreq) {
super(vreq); super(vreq);
String[] values = vreq.getParameterValues(PARAMETER_DELETE_ACCOUNT); String[] values = vreq.getParameterValues(PARAMETER_DELETE_ACCOUNT);

View file

@ -55,14 +55,6 @@ public class UserAccountsEditPage extends UserAccountsPage {
throw new RuntimeException("UserAccountsEditPage.getUpdatedAccount() not implemented."); throw new RuntimeException("UserAccountsEditPage.getUpdatedAccount() not implemented.");
} }
/**
*
*/
public void parseParametersAndValidate() {
// TODO Auto-generated method stub
throw new RuntimeException("UserAccountsEditPage.parseParametersAndValidate() not implemented.");
}
/** /**
* @return * @return
*/ */

View file

@ -20,8 +20,6 @@ import edu.cornell.mannlib.vitro.webapp.beans.UserAccount.Status;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsOrdering.Direction; import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsOrdering.Direction;
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsOrdering.Field; import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsOrdering.Field;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.TemplateResponseValues;
@ -100,7 +98,7 @@ public class UserAccountsListPage extends UserAccountsPage {
userAccountsModel, criteria); userAccountsModel, criteria);
Map<String, Object> body = buildTemplateBodyMap(selection); Map<String, Object> body = buildTemplateBodyMap(selection);
body.put("newUserAccount", new UserAccountWrapper(vreq, userAccount, body.put("newUserAccount", new UserAccountWrapper(userAccount,
Collections.<String> emptyList())); Collections.<String> emptyList()));
return new TemplateResponseValues(TEMPLATE_NAME, body); return new TemplateResponseValues(TEMPLATE_NAME, body);
@ -215,7 +213,7 @@ public class UserAccountsListPage extends UserAccountsPage {
UserAccountsSelection selection) { UserAccountsSelection selection) {
List<UserAccountWrapper> list = new ArrayList<UserAccountWrapper>(); List<UserAccountWrapper> list = new ArrayList<UserAccountWrapper>();
for (UserAccount account : selection.getUserAccounts()) { for (UserAccount account : selection.getUserAccounts()) {
list.add(new UserAccountWrapper(vreq, account, list.add(new UserAccountWrapper(account,
findPermissionSetLabels(account))); findPermissionSetLabels(account)));
} }
return list; return list;
@ -240,14 +238,11 @@ public class UserAccountsListPage extends UserAccountsPage {
private final List<String> permissionSets; private final List<String> permissionSets;
private final String editUrl; private final String editUrl;
public UserAccountWrapper(VitroRequest vreq, UserAccount account, public UserAccountWrapper(UserAccount account,
List<String> permissionSets) { List<String> permissionSets) {
this.account = account; this.account = account;
this.permissionSets = permissionSets; this.permissionSets = permissionSets;
this.editUrl = UserAccountsPage.editAccountUrl(account.getUri());
UrlBuilder urlBuilder = new UrlBuilder(vreq.getAppBean());
this.editUrl = urlBuilder.getPortalUrl("/userAccounts/edit",
new ParamMap("editAccount", account.getUri()));
} }
public String getUri() { public String getUri() {

View file

@ -20,6 +20,7 @@ import com.hp.hpl.jena.ontology.OntModel;
import edu.cornell.mannlib.vitro.webapp.beans.PermissionSet; import edu.cornell.mannlib.vitro.webapp.beans.PermissionSet;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder.ParamMap;
import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao; import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao;
import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
import edu.cornell.mannlib.vitro.webapp.dao.jena.OntModelSelector; import edu.cornell.mannlib.vitro.webapp.dao.jena.OntModelSelector;
@ -102,11 +103,16 @@ public abstract class UserAccountsPage {
protected Map<String, String> buildUrlsMap() { protected Map<String, String> buildUrlsMap() {
Map<String, String> map = new HashMap<String, String>(); Map<String, String> map = new HashMap<String, String>();
map.put("list", UrlBuilder.getUrl("/userAccounts/list")); map.put("list", UrlBuilder.getUrl("/accountsAdmin/list"));
map.put("add", UrlBuilder.getUrl("/userAccounts/add")); map.put("add", UrlBuilder.getUrl("/accountsAdmin/add"));
map.put("delete", UrlBuilder.getUrl("/userAccounts/delete")); map.put("delete", UrlBuilder.getUrl("/accountsAdmin/delete"));
map.put("createPassword", UrlBuilder.getUrl("/accounts/createPassword"));
return map; return map;
} }
protected static String editAccountUrl(String uri) {
return UrlBuilder.getUrl("/accountsAdmin/edit",
new ParamMap("editAccount", uri));
}
} }

View file

@ -0,0 +1,94 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.accounts.admin;
import java.util.Collection;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.usepages.ManageUserAccounts;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsAddPage;
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsDeleter;
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsEditPage;
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsListPage;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
/**
* Parcel out the different actions required of the Administrators portion of the UserAccounts GUI.
*/
public class UserAccountsAdminController extends FreemarkerHttpServlet {
private static final Log log = LogFactory
.getLog(UserAccountsAdminController.class);
private static final String ACTION_ADD = "/add";
private static final String ACTION_DELETE = "/delete";
private static final String ACTION_EDIT = "/edit";
@Override
protected Actions requiredActions(VitroRequest vreq) {
return new Actions(new ManageUserAccounts());
}
@Override
protected ResponseValues processRequest(VitroRequest vreq) {
if (log.isDebugEnabled()) {
dumpRequestParameters(vreq);
}
String action = vreq.getPathInfo();
log.debug("action = '" + action + "'");
if (ACTION_ADD.equals(action)) {
return handleAddRequest(vreq);
} else if (ACTION_EDIT.equals(action)) {
return handleEditRequest(vreq);
} else if (ACTION_DELETE.equals(action)) {
return handleDeleteRequest(vreq);
} else {
return handleListRequest(vreq);
}
}
private ResponseValues handleAddRequest(VitroRequest vreq) {
UserAccountsAddPage page = new UserAccountsAddPage(vreq);
if (page.isSubmit() && page.isValid()) {
page.createNewAccount();
UserAccountsListPage listPage = new UserAccountsListPage(vreq);
return listPage.showPageWithNewAccount(page.getAddedAccount(),
page.wasPasswordEmailSent());
} else {
return page.showPage();
}
}
private ResponseValues handleEditRequest(VitroRequest vreq) {
UserAccountsEditPage page = new UserAccountsEditPage(vreq);
if (page.isSubmit() && page.isValid()) {
page.updateAccount();
UserAccountsListPage listPage = new UserAccountsListPage(vreq);
return listPage.showPageWithUpdatedAccount(
page.getUpdatedAccount(), page.wasPasswordEmailSent());
} else {
return page.showPage();
}
}
private ResponseValues handleDeleteRequest(VitroRequest vreq) {
UserAccountsDeleter deleter = new UserAccountsDeleter(vreq);
Collection<String> deletedUris = deleter.delete();
return new UserAccountsListPage(vreq)
.showPageWithDeletions(deletedUris);
}
private ResponseValues handleListRequest(VitroRequest vreq) {
UserAccountsListPage page = new UserAccountsListPage(vreq);
return page.showPage();
}
}

View file

@ -0,0 +1,72 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.controller.accounts.user;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.Actions;
import edu.cornell.mannlib.vitro.webapp.beans.DisplayMessage;
import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsCreatePasswordPage;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.RedirectResponseValues;
import edu.cornell.mannlib.vitro.webapp.controller.freemarker.responsevalues.ResponseValues;
/**
* Parcel out the different actions required of the UserAccounts GUI.
*/
public class UserAccountsUserController extends FreemarkerHttpServlet {
private static final Log log = LogFactory
.getLog(UserAccountsUserController.class);
public static final String BOGUS_STANDARD_MESSAGE = "Request failed. Please contact your system administrator.";
private static final String ACTION_CREATE_PASSWORD = "/createPassword";
@Override
protected Actions requiredActions(VitroRequest vreq) {
return Actions.AUTHORIZED;
}
@Override
protected ResponseValues processRequest(VitroRequest vreq) {
if (log.isDebugEnabled()) {
dumpRequestParameters(vreq);
}
String action = vreq.getPathInfo();
log.debug("action = '" + action + "'");
if (ACTION_CREATE_PASSWORD.equals(action)) {
return handleCreatePasswordRequest(vreq);
} else {
return handleInvalidRequest(vreq);
}
}
private ResponseValues handleCreatePasswordRequest(VitroRequest vreq) {
UserAccountsCreatePasswordPage page = new UserAccountsCreatePasswordPage(
vreq);
if (page.isBogus()) {
return showHomePage(vreq, page.getBogusMessage());
} else if (page.isSubmit() && page.isValid()) {
page.createPassword();
return showHomePage(vreq,
"Your password has been saved. Please log in.");
} else {
return page.showPage();
}
}
private ResponseValues handleInvalidRequest(VitroRequest vreq) {
return showHomePage(vreq, BOGUS_STANDARD_MESSAGE);
}
private ResponseValues showHomePage(VitroRequest vreq, String message) {
DisplayMessage.setMessage(vreq, message);
return new RedirectResponseValues("/");
}
}

View file

@ -124,7 +124,7 @@ public class SiteAdminController extends FreemarkerHttpServlet {
urls.put("users", urlBuilder.getPortalUrl("/listUsers")); urls.put("users", urlBuilder.getPortalUrl("/listUsers"));
} }
if (PolicyHelper.isAuthorizedForActions(vreq, new ManageUserAccounts())) { if (PolicyHelper.isAuthorizedForActions(vreq, new ManageUserAccounts())) {
urls.put("userList", urlBuilder.getPortalUrl("/userAccounts")); urls.put("userList", urlBuilder.getPortalUrl("/accountsAdmin"));
} }
if (PolicyHelper.isAuthorizedForActions(vreq, new EditSiteInformation())) { if (PolicyHelper.isAuthorizedForActions(vreq, new EditSiteInformation())) {

View file

@ -24,6 +24,18 @@
<#assign errorMessage = "You must select a role." /> <#assign errorMessage = "You must select a role." />
</#if> </#if>
<#if errorPasswordIsEmpty??>
<#assign errorMessage = "No password supplied." />
</#if>
<#if errorPasswordIsWrongLength??>
<#assign errorMessage = "Password must be between ${minimumLength} and ${maximumLength} characters." />
</#if>
<#if errorPasswordsDontMatch??>
<#assign errorMessage = "Passwords do not match." />
</#if>
<#if errorMessage?has_content> <#if errorMessage?has_content>
<section id="error-alert" role="alert"> <section id="error-alert" role="alert">
<img src="${urls.images}/iconAlert.png" width="24" height="24" alert="Error alert icon"/> <img src="${urls.images}/iconAlert.png" width="24" height="24" alert="Error alert icon"/>
@ -52,6 +64,14 @@
<br /> <br />
</#list> </#list>
<#if !emailIsEnabled??>
<label for="initial-password">Initial password<span class="requiredHint"> *</span></label>
<input type="password" name="initialPassword" value="${initialPassword}" id="initial-password" role="input "/>
<label for="confirm-password">Confirm initial password<span class="requiredHint"> *</span></label>
<input type="text" name="confirmPassword" value="${confirmPassword}" id="confirm-password" role="input "/>
</#if>
<p>Associate a profile with this account</p> <p>Associate a profile with this account</p>
<input type="radio" name="associate" value="yes" role="radio" <#if associate??>checked</#if> id="associate" /> <input type="radio" name="associate" value="yes" role="radio" <#if associate??>checked</#if> id="associate" />
<label class="inline" for="associate"> Yes</label> <label class="inline" for="associate"> Yes</label>
@ -63,11 +83,13 @@
<input type="checkbox" name="resetPassword" value="" id="reset-password" role="checkbox" /> <input type="checkbox" name="resetPassword" value="" id="reset-password" role="checkbox" />
<label class="inline" for="reset-password"> Reset password</label> <label class="inline" for="reset-password"> Reset password</label>
<#if emailIsEnabled??>
<p class="note"> <p class="note">
Note: An email will be sent to the address entered above Note: An email will be sent to the address entered above
notifying that an account has been created. notifying that an account has been created.
It will include instructions for activating the account and creating a password. It will include instructions for activating the account and creating a password.
</p> </p>
</#if>
<input type="submit" name="submitAdd" value="Add new account" class="submit"/> or <a href="${formUrls.list}">Cancel</a> <input type="submit" name="submitAdd" value="Add new account" class="submit"/> or <a href="${formUrls.list}">Cancel</a>

View file

@ -0,0 +1,49 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#-- Template for adding a user account -->
<h3>Add new account</h3>
<#if errorPasswordIsEmpty??>
<#assign errorMessage = "No password supplied." />
</#if>
<#if errorPasswordIsWrongLength??>
<#assign errorMessage = "Password must be between ${minimumLength} and ${maximumLength} characters." />
</#if>
<#if errorPasswordsDontMatch??>
<#assign errorMessage = "Passwords do not match." />
</#if>
<#if errorMessage?has_content>
<section id="error-alert" role="alert">
<img src="${urls.images}/iconAlert.png" width="24" height="24" alert="Error alert icon"/>
<p>${errorMessage}</p>
</section>
</#if>
<section id="add-account" role="region">
<fieldset>
<legend>Add new account</legend>
<form method="POST" action="${formUrls.createPassword}" class="customForm" role="create password">
<input type="hidden" name="user" value="${userAccount.emailAddress}" />
<input type="hidden" name="key" value="${userAccount.passwordLinkExpiresHash}" />
<label for="password">Password<span class="requiredHint"> *</span></label>
<input type="password" name="password" value="${password}" id="password" role="input "/>
<p>Minimum of ${minimumLength} characters in length.</p>
<label for="confirm-password">Confirm Password<span class="requiredHint"> *</span></label>
<input type="password" name="confirmPassword" value="${confirmPassword}" id="confirm-password" role="input "/>
<input type="submit" name="submitCreatePassword" value="Save changes" class="submit"/>
<p class="requiredHint">* required fields</p>
</form>
</fieldset>
</section>
${stylesheets.add('<link rel="stylesheet" href="${urls.base}/edit/forms/css/customForm.css" />')}

View file

@ -0,0 +1,26 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#-- Confirmation that an account has been created. -->
<html>
<head>
<title>${subjectLine}</title>
</head>
<body>
<p>
${userAccount.firstName} ${userAccount.lastName}
</p>
<p>
<strong>Password successfully created.</strong>
</p>
<p>
Yout new password associated with ${userAccount.emailAddress} has been created.
</p>
<p>
Thank you.
</p>
</body>
</html>

View file

@ -0,0 +1,12 @@
<#-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<#-- Confirmation that an account has been created. -->
${userAccount.firstName} ${userAccount.lastName}
Password successfully created.
Your new password associated with ${userAccount.emailAddress}
has been created.
Thank you.