diff --git a/webapp/build.xml b/webapp/build.xml index 41b3269c7..ee1a4280a 100644 --- a/webapp/build.xml +++ b/webapp/build.xml @@ -114,8 +114,8 @@ deploy - Deploy the application directly into the Tomcat webapps directory. message="${deploy.properties.file} must contain a value for VitroConnection.DataSource.username" /> - + diff --git a/webapp/config/example.deploy.properties b/webapp/config/example.deploy.properties index 9148818b3..339405801 100644 --- a/webapp/config/example.deploy.properties +++ b/webapp/config/example.deploy.properties @@ -83,11 +83,11 @@ VitroConnection.DataSource.validationQuery = SELECT 1 # vitro.local.solr.url = # -# The name of your first admin user for the Vitro application. The password -# for this user is initially set to "defaultAdmin", but you will be asked to +# The email address of the root user for the VIVO application. The password +# for this user is initially set to "rootPassword", but you will be asked to # change the password the first time you log in. # -initialAdminUser = defaultAdmin +rootUser.emailAddress = root@myDomain.com # # How is a logged-in user associated with a particular Individual? One way is diff --git a/webapp/config/web.xml b/webapp/config/web.xml index 7140c90f7..31e263e37 100644 --- a/webapp/config/web.xml +++ b/webapp/config/web.xml @@ -105,11 +105,11 @@ - + @@ -151,6 +151,10 @@ + + edu.cornell.mannlib.vitro.webapp.auth.policy.RootUserPolicy$Setup + + - - UsersListingController - edu.cornell.mannlib.vitro.webapp.controller.edit.listing.UsersListingController - - - UsersListingController - /listUsers - - AccountsAdmin edu.cornell.mannlib.vitro.webapp.controller.accounts.admin.UserAccountsAdminController diff --git a/webapp/src/edu/cornell/mannlib/vedit/beans/LoginStatusBean.java b/webapp/src/edu/cornell/mannlib/vedit/beans/LoginStatusBean.java index 15cdbbf43..04ec6f276 100644 --- a/webapp/src/edu/cornell/mannlib/vedit/beans/LoginStatusBean.java +++ b/webapp/src/edu/cornell/mannlib/vedit/beans/LoginStatusBean.java @@ -9,8 +9,8 @@ import javax.servlet.http.HttpSession; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import edu.cornell.mannlib.vitro.webapp.beans.User; -import edu.cornell.mannlib.vitro.webapp.dao.UserDao; +import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; +import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; /** @@ -81,7 +81,7 @@ public class LoginStatusBean { /** * Get the current user, or null if not logged in. */ - public static User getCurrentUser(HttpServletRequest request) { + public static UserAccount getCurrentUser(HttpServletRequest request) { if (request == null) { return null; } @@ -91,7 +91,7 @@ public class LoginStatusBean { /** * Get the current user, or null if not logged in. */ - public static User getCurrentUser(HttpSession session) { + public static UserAccount getCurrentUser(HttpSession session) { if (session == null) { return null; } @@ -108,14 +108,14 @@ public class LoginStatusBean { return null; } - UserDao userDao = wadf.getUserDao(); - if (userDao == null) { - log.error("No UserDao"); + UserAccountsDao userAccountsDao = wadf.getUserAccountsDao(); + if (userAccountsDao == null) { + log.error("No UserAccountsDao"); return null; } String userUri = getBean(session).getUserURI(); - return userDao.getUserByURI(userUri); + return userAccountsDao.getUserAccountByUri(userUri); } // ---------------------------------------------------------------------- diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/identifier/common/CommonIdentifierBundleFactory.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/identifier/common/CommonIdentifierBundleFactory.java index 8176ca3b2..b2353e6ae 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/identifier/common/CommonIdentifierBundleFactory.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/identifier/common/CommonIdentifierBundleFactory.java @@ -22,8 +22,9 @@ import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundleFactory; import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel; import edu.cornell.mannlib.vitro.webapp.beans.Individual; import edu.cornell.mannlib.vitro.webapp.beans.SelfEditingConfiguration; -import edu.cornell.mannlib.vitro.webapp.beans.User; +import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao; +import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao; import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; /** @@ -49,6 +50,7 @@ public class CommonIdentifierBundleFactory implements IdentifierBundleFactory { ArrayIdentifierBundle bundle = new ArrayIdentifierBundle(); bundle.addAll(createUserIdentifiers(req)); + bundle.addAll(createRootUserIdentifiers(req)); bundle.addAll(createRoleLevelIdentifiers(req)); bundle.addAll(createBlacklistOrAssociatedIndividualIdentifiers(req)); @@ -68,6 +70,16 @@ public class CommonIdentifierBundleFactory implements IdentifierBundleFactory { } } + private Collection createRootUserIdentifiers( + HttpServletRequest req) { + UserAccount user = LoginStatusBean.getCurrentUser(req); + if (isRootUser(user)) { + return Collections.singleton(new IsRootUser()); + } else { + return Collections.emptySet(); + } + } + /** * Create an identifier that shows the role level of the current user, or * PUBLIC if the user is not logged in. @@ -100,16 +112,21 @@ public class CommonIdentifierBundleFactory implements IdentifierBundleFactory { return ids; } + /** + * Get all Individuals associated with the current user. + * + * TODO Currently only uses the matching property. Should also use + * "mayEditAs" type of association. + */ private Collection getAssociatedIndividuals( HttpServletRequest req) { Collection individuals = new ArrayList(); - User user = LoginStatusBean.getCurrentUser(req); + UserAccount user = LoginStatusBean.getCurrentUser(req); if (user == null) { log.debug("No Associated Individuals: not logged in."); return individuals; } - String username = user.getUsername(); WebappDaoFactory wdf = (WebappDaoFactory) context .getAttribute("webappDaoFactory"); @@ -121,25 +138,30 @@ public class CommonIdentifierBundleFactory implements IdentifierBundleFactory { IndividualDao indDao = wdf.getIndividualDao(); SelfEditingConfiguration sec = SelfEditingConfiguration.getBean(req); - String uri = sec.getIndividualUriFromUsername(indDao, username); - if (uri == null) { - log.debug("Could not find an Individual with a netId of " - + username); - return individuals; - } + individuals.addAll(sec.getAssociatedIndividuals(indDao, user)); - Individual ind = indDao.getIndividualByURI(uri); - if (ind == null) { - log.warn("Found a URI for the netId " + username - + " but could not build Individual"); - return individuals; - } - log.debug("Found an Individual for netId " + username + " URI: " + uri); - - individuals.add(ind); return individuals; } + /** + * Is this user a root user? + */ + private boolean isRootUser(UserAccount user) { + if (user == null) { + return false; + } + + WebappDaoFactory wdf = (WebappDaoFactory) context + .getAttribute("webappDaoFactory"); + if (wdf == null) { + log.error("Could not get a WebappDaoFactory from the ServletContext"); + return false; + } + + UserAccountsDao uaDao = wdf.getUserAccountsDao(); + return uaDao.isRootUser(user); + } + @Override public String toString() { return this.getClass().getSimpleName() + " - " + hashCode(); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/identifier/common/IsRootUser.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/identifier/common/IsRootUser.java new file mode 100644 index 000000000..a41c2ab04 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/identifier/common/IsRootUser.java @@ -0,0 +1,21 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.auth.identifier.common; + +import edu.cornell.mannlib.vitro.webapp.auth.identifier.Identifier; +import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle; + +/** + * The current user is a root user. + */ +public class IsRootUser extends AbstractCommonIdentifier implements Identifier { + public static boolean isRootUser(IdentifierBundle ids) { + return !getIdentifiersForClass(ids, IsRootUser.class).isEmpty(); + } + + @Override + public String toString() { + return "IsRootUser"; + } + +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/PermissionSetsLoader.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/PermissionSetsLoader.java index a35877afb..32f8f6519 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/PermissionSetsLoader.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/permissions/PermissionSetsLoader.java @@ -30,6 +30,11 @@ public class PermissionSetsLoader implements ServletContextListener { private static final Log log = LogFactory .getLog(PermissionSetsLoader.class); + public static final String URI_SELF_EDITOR = "http://permissionSet-1"; + public static final String URI_EDITOR = "http://permissionSet-4"; + public static final String URI_CURATOR = "http://permissionSet-5"; + public static final String URI_DBA = "http://permissionSet-50"; + @Override public void contextInitialized(ServletContextEvent sce) { ServletContext ctx = sce.getServletContext(); @@ -46,10 +51,10 @@ public class PermissionSetsLoader implements ServletContextListener { .getUserAccountsModel(); ModelWrapper wrapper = new ModelWrapper(model); - wrapper.createPermissionSet("1", "Self Editor"); - wrapper.createPermissionSet("2", "Editor"); - wrapper.createPermissionSet("3", "Curator"); - wrapper.createPermissionSet("4", "Site Admin"); + wrapper.createPermissionSet(URI_SELF_EDITOR, "Self Editor"); + wrapper.createPermissionSet(URI_EDITOR, "Editor"); + wrapper.createPermissionSet(URI_CURATOR, "Curator"); + wrapper.createPermissionSet(URI_DBA, "Site Admin"); } catch (Exception e) { log.error("could not run PermissionSetsLoader" + e); AbortStartup.abortStartup(ctx); @@ -77,9 +82,7 @@ public class PermissionSetsLoader implements ServletContextListener { permissionSet = model.createResource(VitroVocabulary.PERMISSIONSET); } - public void createPermissionSet(String uriSuffix, String label) { - String uri = "http://permissionSet-" + uriSuffix; - + public void createPermissionSet(String uri, String label) { model.enterCriticalSection(Lock.WRITE); try { Resource r = model.createResource(uri); diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/RootUserPolicy.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/RootUserPolicy.java new file mode 100644 index 000000000..362fcba1e --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/auth/policy/RootUserPolicy.java @@ -0,0 +1,164 @@ +/* $This file is distributed under the terms of the license in /doc/license.txt$ */ + +package edu.cornell.mannlib.vitro.webapp.auth.policy; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import com.hp.hpl.jena.ontology.OntModel; +import com.hp.hpl.jena.rdf.model.Resource; +import com.hp.hpl.jena.shared.Lock; +import com.hp.hpl.jena.vocabulary.RDF; + +import edu.cornell.mannlib.vitro.webapp.auth.identifier.IdentifierBundle; +import edu.cornell.mannlib.vitro.webapp.auth.identifier.common.IsRootUser; +import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.Authorization; +import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyDecision; +import edu.cornell.mannlib.vitro.webapp.auth.policy.ifaces.PolicyIface; +import edu.cornell.mannlib.vitro.webapp.auth.requestedAction.ifaces.RequestedAction; +import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; +import edu.cornell.mannlib.vitro.webapp.beans.UserAccount.Status; +import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties; +import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator; +import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao; +import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; +import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; +import edu.cornell.mannlib.vitro.webapp.dao.jena.ModelContext; +import edu.cornell.mannlib.vitro.webapp.servlet.setup.AbortStartup; + +/** + * If the user has an IsRootUser identifier, they can do anything! + * + * On setup, check to see that there is a root user. If not, create one. If we + * can't create one, abort. + */ +public class RootUserPolicy implements PolicyIface { + private static final Log log = LogFactory.getLog(RootUserPolicy.class); + + private static final String PROPERTY_ROOT_USER_EMAIL = "rootUser.emailAddress"; + private static final String ROOT_USER_INITIAL_PASSWORD = "rootPassword"; + + /** + * This is the entire policy. If you are a root user, you are authorized. + */ + @Override + public PolicyDecision isAuthorized(IdentifierBundle whoToAuth, + RequestedAction whatToAuth) { + if (IsRootUser.isRootUser(whoToAuth)) { + return new BasicPolicyDecision(Authorization.AUTHORIZED, + "RootUserPolicy: approved"); + } else { + return new BasicPolicyDecision(Authorization.INCONCLUSIVE, + "not root user"); + } + } + + // ---------------------------------------------------------------------- + // Setup class + // ---------------------------------------------------------------------- + + public static class Setup implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent sce) { + ServletContext ctx = sce.getServletContext(); + + if (AbortStartup.isStartupAborted(ctx)) { + return; + } + + try { + UserAccountsDao uaDao = getUserAccountsDao(ctx); + OntModel userAccountsModel = getUserAccountsModel(ctx); + + if (!rootUserExists(uaDao)) { + createRootUser(ctx, uaDao, userAccountsModel); + } + + ServletPolicyList.addPolicy(ctx, new RootUserPolicy()); + } catch (Exception e) { + log.error("could not run " + this.getClass().getSimpleName() + + ": " + e); + AbortStartup.abortStartup(ctx); + throw new RuntimeException(e); + } + } + + private UserAccountsDao getUserAccountsDao(ServletContext ctx) { + WebappDaoFactory wadf = (WebappDaoFactory) ctx + .getAttribute("webappDaoFactory"); + if (wadf == null) { + throw new IllegalStateException( + "No webappDaoFactory on the servlet context"); + } + return wadf.getUserAccountsDao(); + } + + private OntModel getUserAccountsModel(ServletContext ctx) { + return ModelContext.getBaseOntModelSelector(ctx) + .getUserAccountsModel(); + } + + private boolean rootUserExists(UserAccountsDao uaDao) { + for (UserAccount ua : uaDao.getAllUserAccounts()) { + if (uaDao.isRootUser(ua)) { + return true; + } + } + return false; + } + + /** + * TODO The first and last name should be left blank, so the user will + * be forced to edit them. However, that's not in place yet. + */ + private void createRootUser(ServletContext ctx, UserAccountsDao uaDao, + OntModel userAccountsModel) { + String emailAddress = ConfigurationProperties.getBean(ctx) + .getProperty(PROPERTY_ROOT_USER_EMAIL); + if (emailAddress == null) { + throw new IllegalStateException( + "deploy.properties must contain a value for '" + + PROPERTY_ROOT_USER_EMAIL + "'"); + } + + if (null != uaDao.getUserAccountByEmail(emailAddress)) { + throw new IllegalStateException("Can't create root user - " + + "an account already exists with email address '" + + emailAddress + "'"); + } + + UserAccount ua = new UserAccount(); + ua.setEmailAddress(emailAddress); + ua.setFirstName("root"); + ua.setLastName("user"); + ua.setMd5Password(Authenticator + .applyMd5Encoding(ROOT_USER_INITIAL_PASSWORD)); + ua.setPasswordChangeRequired(true); + ua.setStatus(Status.ACTIVE); + + uaDao.insertUserAccount(ua); + + userAccountsModel.enterCriticalSection(Lock.WRITE); + try { + Resource r = userAccountsModel.getResource(ua.getUri()); + Resource t = userAccountsModel + .getResource(VitroVocabulary.USERACCOUNT_ROOT_USER); + userAccountsModel.add(r, RDF.type, t); + } finally { + userAccountsModel.leaveCriticalSection(); + } + + log.info("Created root user as '" + emailAddress + "'"); + } + + @Override + public void contextDestroyed(ServletContextEvent sce) { + // Nothing to destroy + } + } +} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/BaseResourceBean.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/BaseResourceBean.java index 4300e2ab0..a82e680ca 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/BaseResourceBean.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/BaseResourceBean.java @@ -2,6 +2,8 @@ package edu.cornell.mannlib.vitro.webapp.beans; +import java.util.Set; + import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; @@ -9,6 +11,7 @@ import org.apache.commons.logging.LogFactory; import org.openrdf.model.impl.URIImpl; import edu.cornell.mannlib.vedit.beans.LoginStatusBean; +import edu.cornell.mannlib.vitro.webapp.auth.permissions.PermissionSetsLoader; import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary; public class BaseResourceBean implements ResourceBean { @@ -69,17 +72,20 @@ public class BaseResourceBean implements ResourceBean { } public static RoleLevel getRoleFromLoginStatus(HttpServletRequest req) { - User u = LoginStatusBean.getCurrentUser(req); + UserAccount u = LoginStatusBean.getCurrentUser(req); if (u == null) { return PUBLIC; - } else if ("1".equals(u.getRoleURI())) { - return SELF; - } else if ("4".equals(u.getRoleURI())) { - return EDITOR; - } else if ("5".equals(u.getRoleURI())) { + } + + Set roles = u.getPermissionSetUris(); + if (roles.contains(PermissionSetsLoader.URI_DBA)) { + return DB_ADMIN; + } else if (roles.contains(PermissionSetsLoader.URI_CURATOR)) { return CURATOR; - } else if ("50".equals(u.getRoleURI())) { - return DB_ADMIN; + } else if (roles.contains(PermissionSetsLoader.URI_EDITOR)) { + return EDITOR; + } else if (roles.contains(PermissionSetsLoader.URI_SELF_EDITOR)) { + return SELF; } else { return PUBLIC; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/SelfEditingConfiguration.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/SelfEditingConfiguration.java index 7e08b280c..ea1706c48 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/SelfEditingConfiguration.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/SelfEditingConfiguration.java @@ -2,6 +2,9 @@ package edu.cornell.mannlib.vitro.webapp.beans; +import java.util.Collections; +import java.util.List; + import javax.servlet.ServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; @@ -64,7 +67,9 @@ public class SelfEditingConfiguration { } private static SelfEditingConfiguration buildBean(HttpSession session) { - String selfEditingIdMatchingProperty = ConfigurationProperties.getBean(session) + ConfigurationProperties config = ConfigurationProperties + .getBean(session); + String selfEditingIdMatchingProperty = config .getProperty(PROPERTY_SELF_EDITING_ID_MATCHING_PROPERTY); return new SelfEditingConfiguration(selfEditingIdMatchingProperty); } @@ -87,25 +92,39 @@ public class SelfEditingConfiguration { } } - public String getIndividualUriFromUsername(IndividualDao indDao, - String username) { + /** + * Get all Individuals associated with this user through the matching + * property. Never returns null. + */ + public List getAssociatedIndividuals(IndividualDao indDao, + UserAccount user) { + if (user == null) { + log.debug("user is null"); + return Collections.emptyList(); + } + return getAssociatedIndividuals(indDao, user.getExternalAuthId()); + } + + /** + * Get all Individuals associated with this externalAuthId through the + * matching property. Never returns null. + */ + public List getAssociatedIndividuals(IndividualDao indDao, + String externalAuthId) { if (indDao == null) { log.warn("No IndividualDao"); - return null; + return Collections.emptyList(); } - if (username == null) { - log.debug("username is null"); - return null; + if (externalAuthId == null) { + log.debug("externalAuthId is null"); + return Collections.emptyList(); } if (selfEditingIdMatchingProperty == null) { log.debug("selfEditingMatchingProperty is null"); - return null; + return Collections.emptyList(); } - - String uri = indDao.getIndividualURIFromNetId(username, - selfEditingIdMatchingProperty); - log.debug("Username=" + username + ", individual URI=" + uri); - return uri; + return indDao.getIndividualsByDataProperty( + selfEditingIdMatchingProperty, externalAuthId); } @Override diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/User.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/User.java deleted file mode 100644 index 67005be08..000000000 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/User.java +++ /dev/null @@ -1,137 +0,0 @@ -/* $This file is distributed under the terms of the license in /doc/license.txt$ */ - -package edu.cornell.mannlib.vitro.webapp.beans; - -import java.text.Collator; -import java.util.Date; - -public class User implements Comparable { - - public final static int MIN_PASSWORD_LENGTH = 6; - public final static int MAX_PASSWORD_LENGTH = 12; - - private String URI = null; - private String namespace = null; - private String localName = null; - private String username = null; - private String oldPassword = null; - private String md5password = null; - private Date modTime = null; - private Date firstTime = null; - private int loginCount = 0; - private String roleURI = null; - private String lastName = null; - private String firstName = null; - - public String getURI() { - return URI; - } - public void setURI(String URI) { - this.URI = URI; - } - - public String getNamespace() { - return namespace; - } - public void setNamespace(String namespace) { - this.namespace = namespace; - } - - public String getLocalName() { - return localName; - } - public void setLocalName(String localName) { - this.localName = localName; - } - - public String getUsername() { - return username; - } - public void setUsername(String username) { - this.username = username; - } - - public String getOldPassword() { - return oldPassword; - } - public void setOldPassword(String oldPassword) { - this.oldPassword = oldPassword; - } - - public String getMd5password() { - return md5password; - } - public void setMd5password(String md5password) { - this.md5password = md5password; - } - - public Date getModTime() { - return modTime; - } - public void setModTime(Date modTime) { - this.modTime = modTime; - } - - public Date getFirstTime() { - return firstTime; - } - public void setFirstTime(Date firstTime) { - this.firstTime = firstTime; - } - - public int getLoginCount() { - return loginCount; - } - public void setLoginCount(int loginCount) { - this.loginCount = loginCount; - } - - public String getRoleURI() { - return roleURI; - } - public void setRoleURI(String roleURI) { - this.roleURI = roleURI; - } - - public String getLastName() { - return lastName; - } - public void setLastName(String lastName) { - this.lastName = lastName; - } - - public String getFirstName() { - return firstName; - } - public void setFirstName(String firstName) { - this.firstName = firstName; - } - - @Override - public int compareTo(User other) { - Collator collator = Collator.getInstance(); - if( this.getUsername() == null && other.getUsername() == null ) - return 0; - else if( this.getUsername() == null ) - return -1; - else if( other.getUsername() == null) - return 1; - else - return collator.compare(this.getUsername(),other.getUsername()); - } - - @Override - public String toString() { - return "User[URI=" + URI + ", namespace=" + namespace + ", localName=" - + localName + ", username=" + username + ", oldPassword=" - + oldPassword + ", md5password=" + md5password + ", modTime=" - + dateToString(modTime) + ", firstTime=" - + dateToString(firstTime) + ", loginCount=" + loginCount - + ", roleURI=" + roleURI + ", lastName=" + lastName - + ", firstName=" + firstName + "]"; - } - - private String dateToString(Date date) { - return (date == null) ? "null" : String.valueOf(date.getTime()); - } -} diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/MailUsersServlet.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/MailUsersServlet.java index 351f10921..647ebcab2 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/MailUsersServlet.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/MailUsersServlet.java @@ -3,6 +3,7 @@ package edu.cornell.mannlib.vitro.webapp.controller; import java.io.IOException; +import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; @@ -22,7 +23,8 @@ import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import edu.cornell.mannlib.vitro.webapp.dao.UserDao; +import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; +import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao; import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory; public class MailUsersServlet extends VitroHttpServlet { @@ -74,10 +76,8 @@ public class MailUsersServlet extends VitroHttpServlet { int recipientCount = 0; String deliveryfrom = null; - UserDao uDao = vreq.getFullWebappDaoFactory().getUserDao(); - // get Individuals that the User mayEditAs - deliverToArray = uDao.getUserAccountEmails(); + deliverToArray = getEmailsForAllUserAccounts(vreq); //Removed all form type stuff b/c recipients pre-configured recipientCount=(deliverToArray == null) ? 0 : deliverToArray.size(); @@ -208,6 +208,18 @@ public class MailUsersServlet extends VitroHttpServlet { } } + + private List getEmailsForAllUserAccounts(VitroRequest vreq) { + UserAccountsDao uaDao = vreq.getFullWebappDaoFactory() + .getUserAccountsDao(); + + List emails = new ArrayList(); + for (UserAccount user : uaDao.getAllUserAccounts()) { + emails.add(user.getEmailAddress()); + } + + return emails; + } @Override public void doPost( HttpServletRequest request, HttpServletResponse response ) diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsAddPageStrategy.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsAddPageStrategy.java index 9de5f2c07..9061030e7 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsAddPageStrategy.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/admin/UserAccountsAddPageStrategy.java @@ -13,6 +13,7 @@ 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.UserAccountsPage; +import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailFactory; import edu.cornell.mannlib.vitro.webapp.email.FreemarkerEmailMessage; @@ -180,7 +181,7 @@ public abstract class UserAccountsAddPageStrategy extends UserAccountsPage { @Override protected void setAdditionalProperties(UserAccount u) { - u.setMd5Password(initialPassword); + u.setMd5Password(Authenticator.applyMd5Encoding(initialPassword)); u.setPasswordChangeRequired(true); u.setStatus(Status.ACTIVE); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsMyAccountPage.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsMyAccountPage.java index 51b8f0a3b..fbcf541ec 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsMyAccountPage.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/accounts/user/UserAccountsMyAccountPage.java @@ -9,15 +9,12 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import edu.cornell.mannlib.vedit.beans.LoginStatusBean; -import edu.cornell.mannlib.vitro.webapp.beans.User; import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.accounts.UserAccountsPage; import edu.cornell.mannlib.vitro.webapp.controller.accounts.admin.UserAccountsEditPage; 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.dao.UserDao; -import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; /** * Handle the "My Account" form display and submission. @@ -57,7 +54,7 @@ public class UserAccountsMyAccountPage extends UserAccountsPage { public UserAccountsMyAccountPage(VitroRequest vreq) { super(vreq); - this.userAccount = getLoggedInUser(); + this.userAccount = LoginStatusBean.getCurrentUser(vreq); this.strategy = UserAccountsMyAccountPageStrategy.getInstance(vreq, this, isExternalAccount()); @@ -111,25 +108,6 @@ public class UserAccountsMyAccountPage extends UserAccountsPage { return errorCode.isEmpty(); } - private UserAccount getLoggedInUser() { - // TODO This is a bogus measure. - // TODO It only works because for now we are not deleting old User - // structures, and there is a new UserAccount with email set to the old - // User username. - String uri = LoginStatusBean.getBean(vreq).getUserURI(); - WebappDaoFactory wdf = (WebappDaoFactory) this.ctx - .getAttribute("webappDaoFactory"); - User u = wdf.getUserDao().getUserByURI(uri); - - UserAccount ua = userAccountsDao.getUserAccountByEmail(u.getUsername()); - if (ua == null) { - throw new IllegalStateException("Couldn't find a UserAccount " - + "for uri: '" + uri + "'"); - } - log.debug("Logged-in user is " + ua); - return ua; - } - private boolean isExternalAccount() { return LoginStatusBean.getBean(vreq).hasExternalAuthentication(); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AdminLoginController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AdminLoginController.java index fd16d03db..66dc2c3ae 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AdminLoginController.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AdminLoginController.java @@ -13,6 +13,7 @@ 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.UserAccount; import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.FreemarkerHttpServlet; import edu.cornell.mannlib.vitro.webapp.controller.freemarker.UrlBuilder; @@ -31,7 +32,7 @@ public class AdminLoginController extends FreemarkerHttpServlet { private static final Log log = LogFactory .getLog(AdminLoginController.class); - public static final String PARAMETER_USERNAME = "username"; + public static final String PARAMETER_EMAIL_ADDRESS = "email"; public static final String PARAMETER_PASSWORD = "password"; public static final String PARAMETER_NEW_PASSWORD = "newPassword"; public static final String PARAMETER_CONFIRM_PASSWORD = "confirmPassword"; @@ -41,7 +42,7 @@ public class AdminLoginController extends FreemarkerHttpServlet { public static final String TEMPLATE_NAME = "adminLogin.ftl"; - private static final String MESSAGE_NO_USERNAME = "errorNoUser"; + private static final String MESSAGE_NO_EMAIL_ADDRESS = "errorNoEmail"; private static final String MESSAGE_NO_PASSWORD = "errorNoPassword"; private static final String MESSAGE_LOGIN_FAILED = "errorLoginFailed"; private static final String MESSAGE_NEW_PASSWORD_REQUIRED = "newPasswordRequired"; @@ -65,32 +66,37 @@ public class AdminLoginController extends FreemarkerHttpServlet { private static class Core { private final Authenticator auth; - private final String username; + private final String emailAddress; private final String password; private final String newPassword; private final String confirmPassword; + private final UserAccount userAccount; public Core(VitroRequest vreq) { this.auth = Authenticator.getInstance(vreq); - this.username = nonNull(vreq.getParameter(PARAMETER_USERNAME)); + this.emailAddress = nonNull(vreq + .getParameter(PARAMETER_EMAIL_ADDRESS)); this.password = nonNull(vreq.getParameter(PARAMETER_PASSWORD)); this.newPassword = nonNull(vreq .getParameter(PARAMETER_NEW_PASSWORD)); this.confirmPassword = nonNull(vreq .getParameter(PARAMETER_CONFIRM_PASSWORD)); - log.debug("Parameters: username='" + username + "', password='" + log.debug("Parameters: email='" + emailAddress + "', password='" + password + "', newPassword='" + newPassword + "', confirmPassword='" + confirmPassword + "'"); + + this.userAccount = this.auth + .getAccountForInternalAuth(emailAddress); } public ResponseValues process() { - if (username.isEmpty() && password.isEmpty()) { + if (emailAddress.isEmpty() && password.isEmpty()) { return showForm(); } - if (username.isEmpty()) { - return showForm(MESSAGE_NO_USERNAME); + if (emailAddress.isEmpty()) { + return showForm(MESSAGE_NO_EMAIL_ADDRESS); } if (password.isEmpty()) { return showForm(MESSAGE_NO_PASSWORD); @@ -122,8 +128,8 @@ public class AdminLoginController extends FreemarkerHttpServlet { } private boolean newPasswordRequired() { - return auth.isCurrentPassword(username, password) - && auth.isPasswordChangeRequired(username); + return auth.isCurrentPassword(userAccount, password) + && (userAccount.isPasswordChangeRequired()); } private boolean isPasswordValidLength(String pw) { @@ -132,11 +138,11 @@ public class AdminLoginController extends FreemarkerHttpServlet { } private boolean tryToLogin() { - if (auth.isCurrentPassword(username, password)) { - auth.recordLoginAgainstUserAccount(username, INTERNAL); + if (auth.isCurrentPassword(userAccount, password)) { + auth.recordLoginAgainstUserAccount(userAccount, INTERNAL); if (!newPassword.isEmpty()) { - auth.recordNewPassword(username, newPassword); + auth.recordNewPassword(userAccount, newPassword); } return true; @@ -148,7 +154,7 @@ public class AdminLoginController extends FreemarkerHttpServlet { private ResponseValues showForm(String... codes) { Map body = new HashMap(); body.put("controllerUrl", UrlBuilder.getUrl(URL_THIS)); - body.put("username", username); + body.put("email", emailAddress); body.put("password", password); body.put("newPassword", newPassword); body.put("confirmPassword", confirmPassword); @@ -158,7 +164,7 @@ public class AdminLoginController extends FreemarkerHttpServlet { } log.debug("showing form with values: " + body); - + return new TemplateResponseValues(TEMPLATE_NAME, body); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/Authenticator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/Authenticator.java index a212fbe1a..7a94665fa 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/Authenticator.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/Authenticator.java @@ -11,7 +11,7 @@ import javax.servlet.http.HttpServletRequest; import org.apache.commons.codec.binary.Hex; import edu.cornell.mannlib.vedit.beans.LoginStatusBean.AuthenticationSource; -import edu.cornell.mannlib.vitro.webapp.beans.User; +import edu.cornell.mannlib.vitro.webapp.beans.UserAccount; /** * The tool that a login process will use to interface with the user records in @@ -55,37 +55,40 @@ public abstract class Authenticator { public static final int PRIVILEGED_TIMEOUT_INTERVAL = 32000; /** - * Does a user by this name exist? + * Get the UserAccount for this external ID, or null if there is none. */ - public abstract boolean isExistingUser(String username); + public abstract UserAccount getAccountForExternalAuth(String externalAuthId); /** - * Does a user by this name have this password? + * Get the UserAccount for this email address, or null if there is none. */ - public abstract boolean isCurrentPassword(String username, + public abstract UserAccount getAccountForInternalAuth(String emailAddress); + + /** + * Internal: does this UserAccount have this password? False if the + * userAccount is null. + */ + public abstract boolean isCurrentPassword(UserAccount userAccount, String clearTextPassword); /** - * Get the user with this name, or null if no such user exists. + * Internal: record a new password for the user. Takes no action if the + * userAccount is null. */ - public abstract User getUserByUsername(String username); + public abstract void recordNewPassword(UserAccount userAccount, + String newClearTextPassword); + + /** + * Is a change in name or email required when the user logs in? + */ + public abstract boolean accountRequiresEditing(UserAccount userAccount); /** * Get the URIs of all individuals associated with this user, whether by a * self-editing property like cornellEmailNetid, or by mayEditAs. */ - public abstract List getAssociatedIndividualUris(String username); - - /** - * Is a password change needed when the user logs in? - */ - public abstract boolean isPasswordChangeRequired(String username); - - /** - * Record a new password for the user. - */ - public abstract void recordNewPassword(String username, - String newClearTextPassword); + public abstract List getAssociatedIndividualUris( + UserAccount userAccount); /** *
@@ -97,7 +100,7 @@ public abstract class Authenticator {
 	 * - notify other users of the model
 	 * 
*/ - public abstract void recordLoginAgainstUserAccount(String username, + public abstract void recordLoginAgainstUserAccount(UserAccount userAccount, AuthenticationSource authSource); /** @@ -106,9 +109,10 @@ public abstract class Authenticator { * info, so no internal user account. * - this involves everything except updating the user record. * + * + * TODO JB This goes away. */ - public abstract void recordLoginWithoutUserAccount(String username, - String individualUri, AuthenticationSource authSource); + public abstract void recordLoginWithoutUserAccount(String individualUri); /** *
@@ -140,4 +144,8 @@ public abstract class Authenticator {
 		}
 	}
 
+	public static boolean isValidEmailAddress(String emailAddress) {
+		// TODO check for valid syntax.
+		return (emailAddress != null) && (!emailAddress.isEmpty());
+	}
 }
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/BasicAuthenticator.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/BasicAuthenticator.java
index 8f0fcfb6b..2135f007f 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/BasicAuthenticator.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/BasicAuthenticator.java
@@ -4,7 +4,6 @@ package edu.cornell.mannlib.vitro.webapp.controller.authenticate;
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Date;
 import java.util.List;
 import java.util.Map;
 
@@ -18,11 +17,12 @@ import org.apache.commons.logging.LogFactory;
 import edu.cornell.mannlib.vedit.beans.LoginStatusBean;
 import edu.cornell.mannlib.vedit.beans.LoginStatusBean.AuthenticationSource;
 import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel;
+import edu.cornell.mannlib.vitro.webapp.beans.Individual;
 import edu.cornell.mannlib.vitro.webapp.beans.SelfEditingConfiguration;
-import edu.cornell.mannlib.vitro.webapp.beans.User;
+import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
 import edu.cornell.mannlib.vitro.webapp.controller.edit.Authenticate;
 import edu.cornell.mannlib.vitro.webapp.dao.IndividualDao;
-import edu.cornell.mannlib.vitro.webapp.dao.UserDao;
+import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao;
 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.LogoutEvent;
@@ -40,75 +40,97 @@ public class BasicAuthenticator extends Authenticator {
 	}
 
 	@Override
-	public boolean isExistingUser(String username) {
-		return getUserByUsername(username) != null;
-	}
-
-	@Override
-	public User getUserByUsername(String username) {
-		UserDao userDao = getUserDao();
-		if (userDao == null) {
+	public UserAccount getAccountForInternalAuth(String emailAddress) {
+		UserAccountsDao userAccountsDao = getUserAccountsDao();
+		if (userAccountsDao == null) {
 			return null;
 		}
-		return userDao.getUserByUsername(username);
+		return userAccountsDao.getUserAccountByEmail(emailAddress);
 	}
 
 	@Override
-	public boolean isCurrentPassword(String username, String clearTextPassword) {
-		User user = getUserDao().getUserByUsername(username);
-		if (user == null) {
-			log.trace("Checking password '" + clearTextPassword
-					+ "' for user '" + username + "', but user doesn't exist.");
+	public UserAccount getAccountForExternalAuth(String externalAuthId) {
+		UserAccountsDao userAccountsDao = getUserAccountsDao();
+		if (userAccountsDao == null) {
+			return null;
+		}
+		return userAccountsDao.getUserAccountByExternalAuthId(externalAuthId);
+	}
+
+	@Override
+	public boolean isCurrentPassword(UserAccount userAccount,
+			String clearTextPassword) {
+		if (userAccount == null) {
 			return false;
 		}
-
-		String md5NewPassword = applyMd5Encoding(clearTextPassword);
-		return md5NewPassword.equals(user.getMd5password());
+		if (clearTextPassword == null) {
+			return false;
+		}
+		String encodedPassword = applyMd5Encoding(clearTextPassword);
+		return encodedPassword.equals(userAccount.getMd5Password());
 	}
 
 	@Override
-	public boolean isPasswordChangeRequired(String username) {
-		User user = getUserDao().getUserByUsername(username);
-		if ((user != null) && (user.getLoginCount() == 0)) {
+	public void recordNewPassword(UserAccount userAccount,
+			String newClearTextPassword) {
+		if (userAccount == null) {
+			log.error("Trying to change password on null user.");
+			return;
+		}
+		userAccount.setMd5Password(applyMd5Encoding(newClearTextPassword));
+		userAccount.setPasswordChangeRequired(false);
+		userAccount.setPasswordLinkExpires(0L);
+		getUserAccountsDao().updateUserAccount(userAccount);
+	}
+
+	@Override
+	public boolean accountRequiresEditing(UserAccount userAccount) {
+		if (userAccount == null) {
+			log.error("Trying to check for valid fields on a null user.");
+			return false;
+		}
+		if (userAccount.getFirstName().isEmpty()) {
 			return true;
-		} else {
-			return false;
 		}
+		if (userAccount.getLastName().isEmpty()) {
+			return true;
+		}
+		if (userAccount.getEmailAddress().isEmpty()) {
+			return true;
+		}
+		if (!isValidEmailAddress(userAccount.getEmailAddress())) {
+			return true;
+		}
+		return false;
 	}
 
 	@Override
-	public void recordNewPassword(String username, String newClearTextPassword) {
-		User user = getUserByUsername(username);
-		if (user == null) {
-			log.error("Trying to change password on non-existent user: "
-					+ username);
-			return;
+	public List getAssociatedIndividualUris(UserAccount userAccount) {
+		List uris = new ArrayList();
+		if (userAccount == null) {
+			return uris;
 		}
-		user.setOldPassword(user.getMd5password());
-		user.setMd5password(applyMd5Encoding(newClearTextPassword));
-		getUserDao().updateUser(user);
+		uris.addAll(getUrisAssociatedBySelfEditorConfig(userAccount));
+		return uris;
 	}
 
 	@Override
-	public void recordLoginAgainstUserAccount(String username,
+	public void recordLoginAgainstUserAccount(UserAccount userAccount,
 			AuthenticationSource authSource) {
-		User user = getUserByUsername(username);
-		if (user == null) {
-			log.error("Trying to record the login of a non-existent user: "
-					+ username);
+		if (userAccount == null) {
+			log.error("Trying to record the login of a null user. ");
 			return;
 		}
 
-		recordLoginOnUserRecord(user);
-
-		String userUri = user.getURI();
-		recordLoginWithOrWithoutUserAccount(userUri, authSource);
+		recordLoginOnUserRecord(userAccount);
+		recordLoginWithOrWithoutUserAccount(userAccount.getUri(), authSource);
 	}
 
+	// TODO JB This goes away.
 	@Override
-	public void recordLoginWithoutUserAccount(String username,
-			String individualUri, AuthenticationSource authSource) {
-		recordLoginWithOrWithoutUserAccount(individualUri, authSource);
+	public void recordLoginWithoutUserAccount(String individualUri) {
+		recordLoginWithOrWithoutUserAccount(individualUri,
+				AuthenticationSource.EXTERNAL);
 	}
 
 	/** This much is in common on login, whether or not you have a user account. */
@@ -124,12 +146,9 @@ public class BasicAuthenticator extends Authenticator {
 	/**
 	 * Update the user record to record the login.
 	 */
-	private void recordLoginOnUserRecord(User user) {
-		user.setLoginCount(user.getLoginCount() + 1);
-		if (user.getFirstTime() == null) { // first login
-			user.setFirstTime(new Date());
-		}
-		getUserDao().updateUser(user);
+	private void recordLoginOnUserRecord(UserAccount userAccount) {
+		userAccount.setLoginCount(userAccount.getLoginCount() + 1);
+		getUserAccountsDao().updateUserAccount(userAccount);
 	}
 
 	/**
@@ -175,54 +194,23 @@ public class BasicAuthenticator extends Authenticator {
 				session.getServletContext(), session);
 	}
 
-	@Override
-	public List getAssociatedIndividualUris(String username) {
+	private List getUrisAssociatedBySelfEditorConfig(UserAccount user) {
 		List uris = new ArrayList();
-		uris.addAll(getUrisAssociatedBySelfEditorConfig(username));
-		uris.addAll(getUrisAssociatedByMayEditAs(username));
-		return uris;
-	}
-
-	private List getUrisAssociatedBySelfEditorConfig(String username) {
-		if (username == null) {
-			return Collections.emptyList();
+		if (user == null) {
+			return uris;
 		}
 
 		IndividualDao iDao = getIndividualDao();
 		if (iDao == null) {
-			return Collections.emptyList();
+			return uris;
 		}
 
-		String selfEditorUri = SelfEditingConfiguration.getBean(request)
-				.getIndividualUriFromUsername(iDao, username);
-		if (selfEditorUri == null) {
-			return Collections.emptyList();
-		} else {
-			return Collections.singletonList(selfEditorUri);
+		List associatedIndividuals = SelfEditingConfiguration
+				.getBean(request).getAssociatedIndividuals(iDao, user);
+		for (Individual ind : associatedIndividuals) {
+			uris.add(ind.getURI());
 		}
-	}
-
-	private List getUrisAssociatedByMayEditAs(String username) {
-		if (username == null) {
-			return Collections.emptyList();
-		}
-
-		UserDao userDao = getUserDao();
-		if (userDao == null) {
-			return Collections.emptyList();
-		}
-
-		User user = userDao.getUserByUsername(username);
-		if (user == null) {
-			return Collections.emptyList();
-		}
-
-		String userUri = user.getURI();
-		if (userUri == null) {
-			return Collections.emptyList();
-		}
-
-		return userDao.getIndividualsUserMayEditAs(userUri);
+		return uris;
 	}
 
 	@Override
@@ -233,42 +221,30 @@ public class BasicAuthenticator extends Authenticator {
 	}
 
 	private void notifyOtherUsersOfLogout(HttpSession session) {
-		LoginStatusBean loginBean = LoginStatusBean.getBean(session);
-		if (!loginBean.isLoggedIn()) {
+		String userUri = LoginStatusBean.getBean(session).getUserURI();
+		if ((userUri == null) || userUri.isEmpty()) {
 			return;
 		}
 
-		UserDao userDao = getUserDao();
-		if (userDao == null) {
-			return;
-		}
-
-		String userUri = loginBean.getUserURI();
-		User user = userDao.getUserByURI(userUri);
-		if (user == null) {
-			log.error("Unable to retrieve user " + userUri + " from model");
-			return;
-		}
-
-		Authenticate.sendLoginNotifyEvent(new LogoutEvent(user.getURI()),
+		Authenticate.sendLoginNotifyEvent(new LogoutEvent(userUri),
 				session.getServletContext(), session);
 	}
 
 	/**
-	 * Get a reference to the UserDao, or null.
+	 * Get a reference to the UserAccountsDao, or null.
 	 */
-	private UserDao getUserDao() {
+	private UserAccountsDao getUserAccountsDao() {
 		WebappDaoFactory wadf = getWebappDaoFactory();
 		if (wadf == null) {
 			return null;
 		}
 
-		UserDao userDao = wadf.getUserDao();
-		if (userDao == null) {
-			log.error("getUserDao: no UserDao");
+		UserAccountsDao userAccountsDao = wadf.getUserAccountsDao();
+		if (userAccountsDao == null) {
+			log.error("getUserAccountsDao: no UserAccountsDao");
 		}
 
-		return userDao;
+		return userAccountsDao;
 	}
 
 	/**
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginExternalAuthReturn.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginExternalAuthReturn.java
index eea0f21e0..b4eca1079 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginExternalAuthReturn.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginExternalAuthReturn.java
@@ -15,6 +15,7 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
 import edu.cornell.mannlib.vedit.beans.LoginStatusBean.AuthenticationSource;
+import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
 
 /**
  * Handle the return from the external authorization login server. If we are
@@ -40,36 +41,44 @@ public class LoginExternalAuthReturn extends BaseLoginServlet {
 	@Override
 	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
 			throws ServletException, IOException {
-		String username = ExternalAuthHelper.getHelper(req).getExternalAuthId(
-				req);
-		List associatedUris = getAuthenticator(req)
-				.getAssociatedIndividualUris(username);
-
-		if (username == null) {
-			log.debug("No username.");
+		String externalAuthId = ExternalAuthHelper.getHelper(req)
+				.getExternalAuthId(req);
+		if (externalAuthId == null) {
+			log.debug("No externalAuthId.");
 			complainAndReturnToReferrer(req, resp, ATTRIBUTE_REFERRER,
 					MESSAGE_LOGIN_FAILED);
-		} else if (getAuthenticator(req).isExistingUser(username)) {
-			log.debug("Logging in as " + username);
-			getAuthenticator(req).recordLoginAgainstUserAccount(username,
+			return;
+		}
+
+		UserAccount userAccount = getAuthenticator(req)
+				.getAccountForExternalAuth(externalAuthId);
+		if (userAccount != null) {
+			log.debug("Logging in as " + userAccount.getUri());
+			getAuthenticator(req).recordLoginAgainstUserAccount(userAccount,
 					AuthenticationSource.EXTERNAL);
 			removeLoginProcessArtifacts(req);
 			new LoginRedirector(req, resp).redirectLoggedInUser();
-		} else if (!associatedUris.isEmpty()) {
-			log.debug("Recognize '" + username + "' as self-editor for "
+			return;
+		}
+
+		List associatedUris = getAuthenticator(req)
+				.getAssociatedIndividualUris(userAccount);
+		// TODO JB - this case should lead to creating a new account.
+		if (!associatedUris.isEmpty()) {
+			log.debug("Recognize '" + externalAuthId + "' as self-editor for "
 					+ associatedUris);
 			String uri = associatedUris.get(0);
 
-			getAuthenticator(req).recordLoginWithoutUserAccount(username, uri,
-					AuthenticationSource.EXTERNAL);
+			getAuthenticator(req).recordLoginWithoutUserAccount(uri);
 			removeLoginProcessArtifacts(req);
 			new LoginRedirector(req, resp).redirectLoggedInUser();
-		} else {
-			log.debug("User is not recognized: " + username);
-			removeLoginProcessArtifacts(req);
-			new LoginRedirector(req, resp)
-					.redirectUnrecognizedExternalUser(username);
+			return;
 		}
+
+		log.debug("User is not recognized: " + externalAuthId);
+		removeLoginProcessArtifacts(req);
+		new LoginRedirector(req, resp)
+				.redirectUnrecognizedExternalUser(externalAuthId);
 	}
 
 	private void removeLoginProcessArtifacts(HttpServletRequest req) {
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginRedirector.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginRedirector.java
index 32e6c28d4..d0746ad92 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginRedirector.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/LoginRedirector.java
@@ -18,10 +18,9 @@ import org.apache.commons.logging.LogFactory;
 import edu.cornell.mannlib.vedit.beans.LoginStatusBean;
 import edu.cornell.mannlib.vitro.webapp.beans.BaseResourceBean.RoleLevel;
 import edu.cornell.mannlib.vitro.webapp.beans.DisplayMessage;
-import edu.cornell.mannlib.vitro.webapp.beans.User;
+import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
 import edu.cornell.mannlib.vitro.webapp.controller.Controllers;
 import edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean;
-import freemarker.template.utility.StringUtil;
 
 /**
  * A user has just completed the login process. What page do we direct them to?
@@ -51,23 +50,22 @@ public class LoginRedirector {
 
 	/** Is there an Individual associated with this user? */
 	private String getAssociatedIndividualUri() {
-		User user = LoginStatusBean.getCurrentUser(request);
-		if (user == null) {
-			log.warn("Not logged in? How did we get here?");
+		UserAccount userAccount = LoginStatusBean.getCurrentUser(request);
+		if (userAccount == null) {
+			log.debug("Not logged in? Must be cancelling the password change");
 			return null;
 		}
-		String username = user.getUsername();
 
 		List uris = Authenticator.getInstance(request)
-				.getAssociatedIndividualUris(username);
+				.getAssociatedIndividualUris(userAccount);
 		if (uris.isEmpty()) {
-			log.debug("'" + username
+			log.debug("'" + userAccount.getEmailAddress()
 					+ "' is not associated with an individual.");
 			return null;
 		} else {
 			String uri = uris.get(0);
-			log.debug("'" + username + "' is associated with an individual: "
-					+ uri);
+			log.debug("'" + userAccount.getEmailAddress()
+					+ "' is associated with an individual: " + uri);
 			return uri;
 		}
 	}
@@ -111,13 +109,13 @@ public class LoginRedirector {
 		String backString = "";
 		String greeting = "";
 
-		User user = LoginStatusBean.getCurrentUser(request);
-		if (user != null) {
-			greeting = user.getUsername();
-			if (user.getLoginCount() > 1) {
+		UserAccount userAccount = LoginStatusBean.getCurrentUser(request);
+		if (userAccount != null) {
+			greeting = userAccount.getEmailAddress();
+			if (userAccount.getLoginCount() > 1) {
 				backString = " back";
 			}
-			String name = user.getFirstName();
+			String name = userAccount.getFirstName();
 			if (!StringUtils.isEmpty(name)) {
 				greeting = name;
 			}
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/ProgramLogin.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/ProgramLogin.java
index af6368315..bdaef9162 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/ProgramLogin.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/authenticate/ProgramLogin.java
@@ -14,13 +14,18 @@ import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
-import edu.cornell.mannlib.vitro.webapp.beans.User;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
 
 /**
  * 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 {
+	private static final Log log = LogFactory.getLog(ProgramLogin.class);
+
 	@Override
 	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
 			throws ServletException, IOException {
@@ -34,16 +39,16 @@ public class ProgramLogin extends HttpServlet {
 	}
 
 	static class ProgramLoginCore {
-		public static final String PARAM_USERNAME = "username";
+		public static final String PARAM_EMAIL_ADDRESS = "email";
 		public static final String PARAM_PASSWORD = "password";
 		public static final String PARAM_NEW_PASSWORD = "newPassword";
 		public static final int ERROR_CODE = 403;
 
-		private static final String MESSAGE_NEED_USERNAME = PARAM_USERNAME
+		private static final String MESSAGE_NEED_EMAIL_ADDRESS = PARAM_EMAIL_ADDRESS
 				+ " parameter is required.";
 		private static final String MESSAGE_NEED_PASSWORD = PARAM_PASSWORD
 				+ " parameter is required.";
-		private static final String MESSAGE_WRONG_USER_OR_PASSWORD = PARAM_USERNAME
+		private static final String MESSAGE_WRONG_USER_OR_PASSWORD = PARAM_EMAIL_ADDRESS
 				+ " or " + PARAM_PASSWORD + " is incorrect.";
 		private static final String MESSAGE_NEED_NEW_PASSWORD = "first-time login: "
 				+ PARAM_NEW_PASSWORD + " parameter is required.";
@@ -63,24 +68,31 @@ public class ProgramLogin extends HttpServlet {
 		private final HttpServletResponse resp;
 		private final Authenticator auth;
 
-		private final String username;
+		private final String emailAddress;
 		private final String password;
 		private final String newPassword;
+		private final UserAccount userAccount;
 
 		ProgramLoginCore(HttpServletRequest req, HttpServletResponse resp) {
 			this.req = req;
 			this.resp = resp;
 
-			this.username = getParameter(PARAM_USERNAME);
+			this.emailAddress = getParameter(PARAM_EMAIL_ADDRESS);
 			this.password = getParameter(PARAM_PASSWORD);
 			this.newPassword = getParameter(PARAM_NEW_PASSWORD);
 
+			log.debug("request: email='" + emailAddress + "', password='"
+					+ password + "', newPassword='" + newPassword + "'");
+
 			this.auth = Authenticator.getInstance(req);
+
+			this.userAccount = auth
+					.getAccountForInternalAuth(this.emailAddress);
 		}
 
 		void process() throws IOException {
-			if (username.isEmpty()) {
-				sendError(MESSAGE_NEED_USERNAME);
+			if (emailAddress.isEmpty()) {
+				sendError(MESSAGE_NEED_EMAIL_ADDRESS);
 				return;
 			}
 			if (password.isEmpty()) {
@@ -92,9 +104,7 @@ public class ProgramLogin extends HttpServlet {
 				return;
 			}
 
-			boolean passwordChangeRequired = isFirstTimeLogin();
-
-			if (!passwordChangeRequired) {
+			if (!isPasswordChangeRequired()) {
 				if (!newPassword.isEmpty()) {
 					sendError(MESSAGE_NEW_PASSWORD_NOT_NEEDED);
 					return;
@@ -104,7 +114,7 @@ public class ProgramLogin extends HttpServlet {
 				return;
 			}
 
-			if (passwordChangeRequired) {
+			if (isPasswordChangeRequired()) {
 				if (newPassword.isEmpty()) {
 					sendError(MESSAGE_NEED_NEW_PASSWORD);
 					return;
@@ -134,8 +144,7 @@ public class ProgramLogin extends HttpServlet {
 		}
 
 		private boolean usernameAndPasswordAreValid() {
-			return auth.isExistingUser(username)
-					&& auth.isCurrentPassword(username, password);
+			return auth.isCurrentPassword(userAccount, password);
 		}
 
 		private boolean newPasswordIsValidPasswordLength() {
@@ -147,18 +156,17 @@ public class ProgramLogin extends HttpServlet {
 			return newPassword.equals(password);
 		}
 
-		private boolean isFirstTimeLogin() {
-			User user = auth.getUserByUsername(username);
-			return (user.getLoginCount() == 0);
+		private boolean isPasswordChangeRequired() {
+			return (userAccount.isPasswordChangeRequired());
 		}
 
 		private void recordLogin() {
-			auth.recordLoginAgainstUserAccount(username, INTERNAL);
+			auth.recordLoginAgainstUserAccount(userAccount, INTERNAL);
 		}
 
 		private void recordLoginWithPasswordChange() {
-			auth.recordNewPassword(username, newPassword);
-			auth.recordLoginAgainstUserAccount(username, INTERNAL);
+			auth.recordNewPassword(userAccount, newPassword);
+			auth.recordLoginAgainstUserAccount(userAccount, INTERNAL);
 		}
 
 		private void sendError(String message) throws IOException {
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/Authenticate.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/Authenticate.java
index 3e1fe3ab0..232e08323 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/Authenticate.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/Authenticate.java
@@ -28,7 +28,7 @@ import com.hp.hpl.jena.ontology.OntModel;
 
 import edu.cornell.mannlib.vedit.beans.LoginStatusBean;
 import edu.cornell.mannlib.vedit.beans.LoginStatusBean.AuthenticationSource;
-import edu.cornell.mannlib.vitro.webapp.beans.User;
+import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
 import edu.cornell.mannlib.vitro.webapp.controller.Controllers;
 import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
 import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
@@ -313,8 +313,9 @@ public class Authenticate extends VitroHttpServlet {
 
 		bean.setUsername(username);
 
-		User user = getAuthenticator(request).getUserByUsername(username);
-		log.trace("User is " + (user == null ? "null" : user.getURI()));
+		UserAccount user = getAuthenticator(request).getAccountForInternalAuth(
+				username);
+		log.trace("User is " + (user == null ? "null" : user.getUri()));
 
 		if (user == null) {
 			bean.setMessage(Message.UNKNOWN_USERNAME, username);
@@ -326,16 +327,16 @@ public class Authenticate extends VitroHttpServlet {
 			return;
 		}
 
-		if (!getAuthenticator(request).isCurrentPassword(username, password)) {
+		if (!getAuthenticator(request).isCurrentPassword(user, password)) {
 			bean.setMessage(Message.INCORRECT_PASSWORD);
 			return;
 		}
 
 		// Username and password are correct. What next?
-		if (isFirstTimeLogin(user)) {
+		if (user.isPasswordChangeRequired()) {
 			transitionToForcedPasswordChange(request);
 		} else {
-			transitionToLoggedIn(request, username);
+			transitionToLoggedIn(request, user);
 		}
 	}
 
@@ -383,13 +384,15 @@ public class Authenticate extends VitroHttpServlet {
 
 		String username = bean.getUsername();
 
-		if (getAuthenticator(request).isCurrentPassword(username, newPassword)) {
+		UserAccount user = getAuthenticator(request).getAccountForInternalAuth(
+				username);
+		if (getAuthenticator(request).isCurrentPassword(user, newPassword)) {
 			bean.setMessage(Message.USING_OLD_PASSWORD);
 			return;
 		}
 
 		// New password is acceptable. Store it and go on.
-		transitionToLoggedIn(request, username, newPassword);
+		transitionToLoggedIn(request, user, newPassword);
 	}
 
 	/**
@@ -400,17 +403,6 @@ public class Authenticate extends VitroHttpServlet {
 		// Nothing to do. No transition.
 	}
 
-	/**
-	 * Has this user ever logged in before?
-	 */
-	private boolean isFirstTimeLogin(User user) {
-		if (user.getLoginCount() == 0) {
-			return true;
-		} else {
-			return false;
-		}
-	}
-
 	/**
 	 * State change: they are starting the login process.
 	 */
@@ -432,9 +424,9 @@ public class Authenticate extends VitroHttpServlet {
 	 * State change: all requirements are satisfied. Log them in.
 	 */
 	private void transitionToLoggedIn(HttpServletRequest request,
-			String username) {
-		log.debug("Completed login: " + username);
-		getAuthenticator(request).recordLoginAgainstUserAccount(username,
+			UserAccount user) {
+		log.debug("Completed login: " + user.getEmailAddress());
+		getAuthenticator(request).recordLoginAgainstUserAccount(user,
 				AuthenticationSource.INTERNAL);
 	}
 
@@ -443,10 +435,11 @@ public class Authenticate extends VitroHttpServlet {
 	 * log them in.
 	 */
 	private void transitionToLoggedIn(HttpServletRequest request,
-			String username, String newPassword) {
-		log.debug("Completed login: " + username + ", password changed.");
-		getAuthenticator(request).recordNewPassword(username, newPassword);
-		getAuthenticator(request).recordLoginAgainstUserAccount(username,
+			UserAccount user, String newPassword) {
+		log.debug("Completed login: " + user.getEmailAddress()
+				+ ", password changed.");
+		getAuthenticator(request).recordNewPassword(user, newPassword);
+		getAuthenticator(request).recordLoginAgainstUserAccount(user,
 				AuthenticationSource.INTERNAL);
 	}
 
@@ -478,7 +471,7 @@ public class Authenticate extends VitroHttpServlet {
 		log.debug("logging in.");
 
 		LoginInProcessFlag.set(vreq);
-		
+
 		String loginProcessPage = LoginProcessBean.getBean(vreq)
 				.getLoginPageUrl();
 		response.sendRedirect(loginProcessPage);
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/N3MultiPartUpload.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/N3MultiPartUpload.java
index 338bb3bea..4c397e20e 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/N3MultiPartUpload.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/N3MultiPartUpload.java
@@ -33,10 +33,9 @@ import com.hp.hpl.jena.rdf.model.StmtIterator;
 import com.hp.hpl.jena.shared.Lock;
 
 import edu.cornell.mannlib.vedit.beans.LoginStatusBean;
+import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
 import edu.cornell.mannlib.vitro.webapp.config.ConfigurationProperties;
 import edu.cornell.mannlib.vitro.webapp.controller.VitroHttpServlet;
-import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
-import edu.cornell.mannlib.vitro.webapp.dao.UserDao;
 import edu.cornell.mannlib.vitro.webapp.dao.jena.event.EditEvent;
 import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.EditConfiguration;
 import edu.cornell.mannlib.vitro.webapp.edit.n3editing.configuration.Field;
@@ -507,12 +506,14 @@ public class N3MultiPartUpload extends VitroHttpServlet {
     }
     
     public void sendUserEmail(HttpServletRequest request, HttpSession session, String uploadFileName) {
-        LoginStatusBean loginBean = LoginStatusBean.getBean(request);
-        String userURI = loginBean.getUserURI();
+    	UserAccount userAccount = LoginStatusBean.getCurrentUser(request);
+    	if (userAccount == null) {
+    		return;
+    	}
+    	
         try{
-	        System.out.println("User URI is " + userURI);
-	        UserDao uDao = (new VitroRequest(request)).getFullWebappDaoFactory().getUserDao();
-	        String email = uDao.getUserEmailAddress(userURI);
+	        System.out.println("User URI is " + userAccount.getUri());
+	        String email = userAccount.getEmailAddress();
 	        String deliveryFrom = "hjk54@cornell.edu";//TO DO: replace with email address to be used
 	        //Now send message
 	        MailUtil mu = new MailUtil(request);
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/UserEditController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/UserEditController.java
deleted file mode 100644
index 49a1038c7..000000000
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/UserEditController.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/* $This file is distributed under the terms of the license in /doc/license.txt$ */
-
-package edu.cornell.mannlib.vitro.webapp.controller.edit;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import edu.cornell.mannlib.vedit.controller.BaseEditController;
-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.beans.Individual;
-import edu.cornell.mannlib.vitro.webapp.beans.IndividualImpl;
-import edu.cornell.mannlib.vitro.webapp.beans.ObjectProperty;
-import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement;
-import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatementImpl;
-import edu.cornell.mannlib.vitro.webapp.beans.User;
-import edu.cornell.mannlib.vitro.webapp.controller.Controllers;
-import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
-import edu.cornell.mannlib.vitro.webapp.dao.UserDao;
-import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
-
-public class UserEditController extends BaseEditController {
-
-    private String[] roleNameStr = new String[51];
-    private static final Log log = LogFactory.getLog(UserEditController.class.getName());
-
-    public UserEditController() {
-        roleNameStr[1] = "self editor";
-        roleNameStr[4] = "editor";
-        roleNameStr[5] = "curator";
-        roleNameStr[50] = "system administrator";
-    }
-
-    @Override
-	public void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException {
-    	if (!isAuthorizedToDisplayPage(request, response, new Actions(new ManageUserAccounts()))) {
-    		return;
-    	}
-
-        VitroRequest vreq = new VitroRequest(request);
-
-        UserDao uDao = vreq.getFullWebappDaoFactory().getUserDao();
-
-        String userURIStr = request.getParameter("uri");
-        User u = null;
-
-        if (userURIStr == null) {
-            throw new ServletException(this.getClass().getName()+" expects user URI in 'uri' request parameter");
-        } else {
-            u = uDao.getUserByURI(userURIStr);
-        }
-
-        if (u == null) {
-            throw new ServletException(this.getClass().getName()+" could not find user "+userURIStr);
-        }
-
-        ArrayList results = new ArrayList();
-        results.add("Email address");
-        results.add("first name");
-        results.add("last name");
-        results.add("login count");
-        results.add("role");
-
-        String EMPTY = "";
-
-        String usernameStr = (u.getUsername() != null) ? u.getUsername() : "";
-        results.add(usernameStr);
-        String firstNameStr = (u.getFirstName() != null) ? u.getFirstName() : EMPTY;
-        results.add(firstNameStr);
-        String lastNameStr = (u.getLastName() != null) ? u.getLastName() : EMPTY;
-        results.add(lastNameStr);
-        String loginCountStr = Integer.toString(u.getLoginCount());
-        results.add(loginCountStr);
-        String roleStr = "";
-        try {
-            roleStr = roleNameStr[Integer.decode(u.getRoleURI())];
-        } catch (Exception e) {}
-        results.add(roleStr);
-
-        request.setAttribute("results",results);
-
-        List mayEditAsUris = uDao.getIndividualsUserMayEditAs(u.getURI());
-        if( mayEditAsUris != null && mayEditAsUris.size() > 0 ){
-            List mayEditAsStmts = 
-                new ArrayList(mayEditAsUris.size());
-            for(String objURI: mayEditAsUris){
-            	Individual editAs = vreq.getFullWebappDaoFactory().getIndividualDao().getIndividualByURI(objURI);
-                ObjectPropertyStatement stmt = new ObjectPropertyStatementImpl();
-                stmt.setSubjectURI(u.getURI());
-                stmt.setPropertyURI(VitroVocabulary.MAY_EDIT_AS);
-                stmt.setObjectURI(objURI);
-                stmt.setObject(editAs);
-                mayEditAsStmts.add(stmt);
-            }
-            request.setAttribute("mayEditAsStmts", mayEditAsStmts);
-        }
-        
-        /* these are set so that we can use the PropertyEditLinks jsp tags */
-        ObjectProperty prop = new ObjectProperty();
-        prop.setURI(VitroVocabulary.MAY_EDIT_AS);
-        request.setAttribute("mayEditObjProp",prop);        
-        Individual entity = new IndividualImpl();
-        entity.setURI(u.getURI());
-        request.setAttribute("entity", entity);
-        
-        request.setAttribute("results", results);
-        request.setAttribute("columncount", new Integer(5));
-        request.setAttribute("suppressquery", "true");
-
-        RequestDispatcher rd = request.getRequestDispatcher(Controllers.BASIC_JSP);
-        request.setAttribute("user", u);
-        request.setAttribute("bodyJsp","/templates/edit/specific/user_edit.jsp");
-        request.setAttribute("title","User Account Control Panel");
-        request.setAttribute("css", "");
-
-        try {
-            rd.forward(request, response);
-        } catch (Exception e) {
-            log.error(this.getClass().getName()+" could not forward to view.");
-            log.error(e.getMessage());
-            log.error(e.getStackTrace());
-        }
-
-    }
-
-    public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException {
-        doPost(request,response);
-    }
-
-}
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/UserRetryController.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/UserRetryController.java
deleted file mode 100644
index 36d5d7c6f..000000000
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/controller/edit/UserRetryController.java
+++ /dev/null
@@ -1,365 +0,0 @@
-/* $This file is distributed under the terms of the license in /doc/license.txt$ */
-
-package edu.cornell.mannlib.vitro.webapp.controller.edit;
-
-import java.io.IOException;
-import java.net.URLEncoder;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-
-import javax.servlet.RequestDispatcher;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import edu.cornell.mannlib.vedit.beans.EditProcessObject;
-import edu.cornell.mannlib.vedit.beans.FormObject;
-import edu.cornell.mannlib.vedit.beans.LoginStatusBean;
-import edu.cornell.mannlib.vedit.beans.Option;
-import edu.cornell.mannlib.vedit.controller.BaseEditController;
-import edu.cornell.mannlib.vedit.forwarder.PageForwarder;
-import edu.cornell.mannlib.vedit.forwarder.impl.UrlForwarder;
-import edu.cornell.mannlib.vedit.listener.ChangeListener;
-import edu.cornell.mannlib.vedit.util.FormUtils;
-import edu.cornell.mannlib.vedit.validator.ValidationObject;
-import edu.cornell.mannlib.vedit.validator.Validator;
-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.beans.User;
-import edu.cornell.mannlib.vitro.webapp.controller.Controllers;
-import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
-import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator;
-import edu.cornell.mannlib.vitro.webapp.dao.UserDao;
-
-public class UserRetryController extends BaseEditController {
-
-    private static final String ROLE_PROTOCOL = "role:/";  // this is weird; need to revisit
-    private static final Log log = LogFactory.getLog(UserRetryController.class.getName());
-
-    @Override
-    public void doPost (HttpServletRequest req, HttpServletResponse response) {
-    	if (!isAuthorizedToDisplayPage(req, response, new Actions(new ManageUserAccounts()))) {
-    		return;
-    	}
-
-    	VitroRequest request = new VitroRequest(req);
-
-        //create an EditProcessObject for this and put it in the session
-        EditProcessObject epo = super.createEpo(request);
-        epo.setDataAccessObject(request.getFullWebappDaoFactory().getVClassDao());
-
-        String action = null;
-        if (epo.getAction() == null) {
-            action = "insert";
-            epo.setAction("insert");
-        } else {
-            action = epo.getAction();
-        }
-
-        UserDao uDao = request.getFullWebappDaoFactory().getUserDao();
-        epo.setDataAccessObject(uDao);
-
-        User userForEditing = null;
-        if (!epo.getUseRecycledBean()){
-            if (request.getParameter("uri") != null) {
-                try {
-                    userForEditing = uDao.getUserByURI(request.getParameter("uri"));
-                    userForEditing.setRoleURI(ROLE_PROTOCOL+userForEditing.getRoleURI());
-                    action = "update";
-                    epo.setAction("udpate");
-                } catch (NullPointerException e) {
-                    log.error("Need to implement 'record not found' error message.");
-                }
-            } else {
-                userForEditing = new User();
-                userForEditing.setRoleURI(ROLE_PROTOCOL+"1");
-            }
-            epo.setOriginalBean(userForEditing);
-        } else {
-            userForEditing = (User) epo.getNewBean();
-        }
-
-        populateBeanFromParams(userForEditing, request);
-
-        //validators
-        Validator v = new PairedPasswordValidator();
-        HashMap> validatorMap = new HashMap>();
-        List vList = Collections.singletonList(v);
-		validatorMap.put("Md5password", vList);
-		validatorMap.put("passwordConfirmation", vList);
-        epo.setValidatorMap(validatorMap);
-
-        //preprocessors
-       
-        //set up any listeners
-        epo.setChangeListenerList(Collections.singletonList(new UserPasswordChangeListener()));
-
-        //make a postinsert pageforwarder that will send us to a new class's fetch screen
-        epo.setPostInsertPageForwarder(new UserInsertPageForwarder());
-        //make a postdelete pageforwarder that will send us to the list of classes
-        epo.setPostDeletePageForwarder(new UrlForwarder("listUsers"));
-
-        //set the getMethod so we can retrieve a new bean after we've inserted it
-        try {
-            Class[] args = new Class[] {String.class};
-            epo.setGetMethod(uDao.getClass().getDeclaredMethod("getUserByURI",args));
-        } catch (NoSuchMethodException e) {
-            log.error(this.getClass().getName()+" could not find the getVClassByURI method");
-        }
-
-        HashMap> optionMap = new HashMap>();
-
-        LoginStatusBean loginBean = LoginStatusBean.getBean(request);
-        List