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..bbb4b0832 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,7 +22,7 @@ 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.WebappDaoFactory; @@ -104,12 +104,12 @@ public class CommonIdentifierBundleFactory implements IdentifierBundleFactory { 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(); + String emailAddress = user.getEmailAddress(); WebappDaoFactory wdf = (WebappDaoFactory) context .getAttribute("webappDaoFactory"); @@ -121,20 +121,20 @@ public class CommonIdentifierBundleFactory implements IdentifierBundleFactory { IndividualDao indDao = wdf.getIndividualDao(); SelfEditingConfiguration sec = SelfEditingConfiguration.getBean(req); - String uri = sec.getIndividualUriFromUsername(indDao, username); + String uri = sec.getIndividualUriFromUsername(indDao, emailAddress); if (uri == null) { log.debug("Could not find an Individual with a netId of " - + username); + + emailAddress); return individuals; } Individual ind = indDao.getIndividualByURI(uri); if (ind == null) { - log.warn("Found a URI for the netId " + username + log.warn("Found a URI for the netId " + emailAddress + " but could not build Individual"); return individuals; } - log.debug("Found an Individual for netId " + username + " URI: " + uri); + log.debug("Found an Individual for netId " + emailAddress + " URI: " + uri); individuals.add(ind); return individuals; 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/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..4096abc0a 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/SelfEditingConfiguration.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/beans/SelfEditingConfiguration.java @@ -87,6 +87,7 @@ public class SelfEditingConfiguration { } } + // TODO JB This should move to UserAccountsDao. public String getIndividualUriFromUsername(IndividualDao indDao, String username) { if (indDao == null) { 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..eca8954af 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;
 
@@ -19,10 +18,10 @@ 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.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 +39,98 @@ 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 UserAccount getAccountForExternalAuth(String externalAuthId) {
+		UserAccountsDao userAccountsDao = getUserAccountsDao();
+		if (userAccountsDao == null) {
+			return null;
+		}
+		return userAccountsDao.getUserAccountByExternalAuthId(externalAuthId);
 	}
 
 	@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 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 List getAssociatedIndividualUris(UserAccount userAccount) {
+		List uris = new ArrayList();
+		if (userAccount == null) {
+			return uris;
+		}
+		uris.addAll(getUrisAssociatedBySelfEditorConfig(userAccount));
+		return uris;
 	}
 
 	@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;
-		}
-		user.setOldPassword(user.getMd5password());
-		user.setMd5password(applyMd5Encoding(newClearTextPassword));
-		getUserDao().updateUser(user);
-	}
-
-	@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,16 +194,8 @@ public class BasicAuthenticator extends Authenticator {
 				session.getServletContext(), session);
 	}
 
-	@Override
-	public List getAssociatedIndividualUris(String username) {
-		List uris = new ArrayList();
-		uris.addAll(getUrisAssociatedBySelfEditorConfig(username));
-		uris.addAll(getUrisAssociatedByMayEditAs(username));
-		return uris;
-	}
-
-	private List getUrisAssociatedBySelfEditorConfig(String username) {
-		if (username == null) {
+	private List getUrisAssociatedBySelfEditorConfig(UserAccount user) {
+		if (user == null) {
 			return Collections.emptyList();
 		}
 
@@ -194,7 +205,7 @@ public class BasicAuthenticator extends Authenticator {
 		}
 
 		String selfEditorUri = SelfEditingConfiguration.getBean(request)
-				.getIndividualUriFromUsername(iDao, username);
+				.getIndividualUriFromUsername(iDao, user.getExternalAuthId());
 		if (selfEditorUri == null) {
 			return Collections.emptyList();
 		} else {
@@ -202,29 +213,6 @@ public class BasicAuthenticator extends Authenticator {
 		}
 	}
 
-	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);
-	}
-
 	@Override
 	public void recordUserIsLoggedOut() {
 		HttpSession session = request.getSession();
@@ -233,44 +221,32 @@ 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;
 	}
-
+	
 	/**
 	 * Get a reference to the IndividualDao, or null.
 	 */
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/dao/UserAccountsDao.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/UserAccountsDao.java
index ab4ab022e..203556434 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/UserAccountsDao.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/UserAccountsDao.java
@@ -28,6 +28,13 @@ public interface UserAccountsDao {
 	 */
 	UserAccount getUserAccountByEmail(String emailAddress);
 
+	/**
+	 * Get the UserAccount for this External Authentication ID
+	 * 
+	 * @return null if the ID is null, or if there is no such UserAccount
+	 */
+	UserAccount getUserAccountByExternalAuthId(String externalAuthId);
+
 	/**
 	 * Create a new UserAccount in the model.
 	 * 
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/UserAccountsDaoFiltering.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/UserAccountsDaoFiltering.java
index ab46abac6..6348a2ad0 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/UserAccountsDaoFiltering.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/filtering/UserAccountsDaoFiltering.java
@@ -37,6 +37,11 @@ public class UserAccountsDaoFiltering extends BaseFiltering implements
 		return innerDao.getUserAccountByEmail(emailAddress);
 	}
 
+	@Override
+	public UserAccount getUserAccountByExternalAuthId(String externalAuthId) {
+		return innerDao.getUserAccountByExternalAuthId(externalAuthId);
+	}
+	
 	@Override
 	public String insertUserAccount(UserAccount userAccount) {
 		return innerDao.insertUserAccount(userAccount);
@@ -61,4 +66,5 @@ public class UserAccountsDaoFiltering extends BaseFiltering implements
 	public Collection getAllPermissionSets() {
 		return innerDao.getAllPermissionSets();
 	}
+
 }
\ No newline at end of file
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJena.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJena.java
index 38a811b50..7cf587a04 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJena.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/dao/jena/UserAccountsDaoJena.java
@@ -103,6 +103,30 @@ public class UserAccountsDaoJena extends JenaBaseDao implements UserAccountsDao
 		return getUserAccountByUri(userUri);
 	}
 
+	@Override
+	public UserAccount getUserAccountByExternalAuthId(String externalAuthId) {
+		if (externalAuthId == null) {
+			return null;
+		}
+		
+		String userUri = null;
+		
+		getOntModel().enterCriticalSection(Lock.READ);
+		try {
+			StmtIterator stmts = getOntModel().listStatements(null,
+					USERACCOUNT_EXTERNAL_AUTH_ID,
+					getOntModel().createLiteral(externalAuthId));
+			if (stmts.hasNext()) {
+				userUri = stmts.next().getSubject().getURI();
+			}
+			stmts.close();
+		} finally {
+			getOntModel().leaveCriticalSection();
+		}
+
+		return getUserAccountByUri(userUri);
+	}
+
 	@Override
 	public String insertUserAccount(UserAccount userAccount) {
 		if (userAccount == null) {
@@ -324,4 +348,5 @@ public class UserAccountsDaoJena extends JenaBaseDao implements UserAccountsDao
 			return ps1.getUri().compareTo(ps2.getUri());
 		}
 	}
+
 }
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateUserAccounts.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateUserAccounts.java
index 36464b6d6..f89e7adab 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateUserAccounts.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/servlet/setup/UpdateUserAccounts.java
@@ -17,6 +17,7 @@ import javax.servlet.ServletContextListener;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
+import edu.cornell.mannlib.vitro.webapp.auth.permissions.PermissionSetsLoader;
 import edu.cornell.mannlib.vitro.webapp.beans.User;
 import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
 import edu.cornell.mannlib.vitro.webapp.beans.UserAccount.Status;
@@ -32,11 +33,6 @@ import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory;
 public class UpdateUserAccounts implements ServletContextListener {
 	private static final Log log = LogFactory.getLog(UpdateUserAccounts.class);
 
-	private static final String URI_PERMISSION_SET_SELF_EDITOR = "http://permissionSet-1";
-	private static final String URI_PERMISSION_SET_EDITOR = "http://permissionSet-2";
-	private static final String URI_PERMISSION_SET_CURATOR = "http://permissionSet-3";
-	private static final String URI_PERMISSION_SET_DBA = "http://permissionSet-4";
-
 	@Override
 	public void contextInitialized(ServletContextEvent sce) {
 		ServletContext ctx = sce.getServletContext();
@@ -149,13 +145,13 @@ public class UpdateUserAccounts implements ServletContextListener {
 		}
 
 		private Set translateFromRoleUri(String roleUri) {
-			String permissionSetUri = URI_PERMISSION_SET_SELF_EDITOR;
+			String permissionSetUri = PermissionSetsLoader.URI_SELF_EDITOR;
 			if ("4".equals(roleUri)) {
-				permissionSetUri = URI_PERMISSION_SET_EDITOR;
+				permissionSetUri = PermissionSetsLoader.URI_EDITOR;
 			} else if ("5".equals(roleUri)) {
-				permissionSetUri = URI_PERMISSION_SET_CURATOR;
+				permissionSetUri = PermissionSetsLoader.URI_CURATOR;
 			} else if ("50".equals(roleUri)) {
-				permissionSetUri = URI_PERMISSION_SET_DBA;
+				permissionSetUri = PermissionSetsLoader.URI_DBA;
 			}
 			return Collections.singleton(permissionSetUri);
 		}
diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/User.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/User.java
index 3f0cfe775..7600fc41c 100644
--- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/User.java
+++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/User.java
@@ -4,6 +4,7 @@ package edu.cornell.mannlib.vitro.webapp.web.templatemodels;
 
 import edu.cornell.mannlib.vedit.beans.LoginStatusBean;
 import edu.cornell.mannlib.vitro.webapp.auth.policy.PolicyHelper;
+import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
 import edu.cornell.mannlib.vitro.webapp.controller.VitroRequest;
 import edu.cornell.mannlib.vitro.webapp.controller.freemarker.RevisionInfoController;
 import edu.cornell.mannlib.vitro.webapp.controller.freemarker.SiteAdminController;
@@ -11,8 +12,7 @@ import edu.cornell.mannlib.vitro.webapp.controller.freemarker.SiteAdminControlle
 public class User extends BaseTemplateModel {
     private final VitroRequest vreq;
 
-    // TODO JB Modify this to use UserAccount instead of User.
-    private final edu.cornell.mannlib.vitro.webapp.beans.User currentUser;
+    private final UserAccount currentUser;
     
     public User(VitroRequest vreq) {
         this.vreq = vreq;
@@ -24,7 +24,7 @@ public class User extends BaseTemplateModel {
     }
     
     public String getEmailAddress() {
-		return (currentUser == null) ? "" : currentUser.getUsername();
+		return (currentUser == null) ? "" : currentUser.getEmailAddress();
     }
     
     public String getLoginName() {
diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AuthenticatorStub.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AuthenticatorStub.java
index 869812943..6171387f9 100644
--- a/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AuthenticatorStub.java
+++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/authenticate/AuthenticatorStub.java
@@ -12,7 +12,7 @@ import javax.servlet.http.HttpServletRequest;
 
 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;
 
 /**
  * A simple stub for unit tests that require an Authenticator. Call setup() to
@@ -67,7 +67,9 @@ public class AuthenticatorStub extends Authenticator {
 	// Stub infrastructure
 	// ----------------------------------------------------------------------
 
-	private final Map usersByName = new HashMap();
+	private final Map usersByEmail = new HashMap();
+	private final Map usersByExternalAuthId = new HashMap();
+
 	private final Map> editingPermissions = new HashMap>();
 	private final Map associatedUris = new HashMap();
 	private final List recordedLogins = new ArrayList();
@@ -79,8 +81,13 @@ public class AuthenticatorStub extends Authenticator {
 		this.request = request;
 	}
 
-	public void addUser(User user) {
-		usersByName.put(user.getUsername(), user);
+	public void addUser(UserAccount user) {
+		usersByEmail.put(user.getEmailAddress(), user);
+
+		String externalAuthId = user.getExternalAuthId();
+		if (!externalAuthId.isEmpty()) {
+			usersByExternalAuthId.put(user.getExternalAuthId(), user);
+		}
 	}
 
 	public void addEditingPermission(String username, String personUri) {
@@ -107,52 +114,55 @@ public class AuthenticatorStub extends Authenticator {
 	// ----------------------------------------------------------------------
 
 	@Override
-	public boolean isExistingUser(String username) {
-		return usersByName.containsKey(username);
+	public UserAccount getAccountForInternalAuth(String emailAddress) {
+		return usersByEmail.get(emailAddress);
 	}
 
 	@Override
-	public User getUserByUsername(String username) {
-		return usersByName.get(username);
+	public UserAccount getAccountForExternalAuth(String externalAuthId) {
+		return usersByExternalAuthId.get(externalAuthId);
 	}
 
 	@Override
-	public List getAssociatedIndividualUris(String username) {
+	public boolean isCurrentPassword(UserAccount userAccount,
+			String clearTextPassword) {
+		if (userAccount == null) {
+			return false;
+		} else {
+			return userAccount.getMd5Password().equals(
+					Authenticator.applyMd5Encoding(clearTextPassword));
+		}
+	}
+
+	@Override
+	public List getAssociatedIndividualUris(UserAccount userAccount) {
 		List uris = new ArrayList();
 
-		if (associatedUris.containsKey(username)) {
-			uris.add(associatedUris.get(username));
+		String emailAddress = userAccount.getEmailAddress();
+		if (associatedUris.containsKey(emailAddress)) {
+			uris.add(associatedUris.get(emailAddress));
 		}
 
-		if (editingPermissions.containsKey(username)) {
-			uris.addAll(editingPermissions.get(username));
+		if (editingPermissions.containsKey(emailAddress)) {
+			uris.addAll(editingPermissions.get(emailAddress));
 		}
 
 		return uris;
 	}
 
 	@Override
-	public boolean isCurrentPassword(String username, String clearTextPassword) {
-		if (!isExistingUser(username)) {
-			return false;
-		}
-		String md5Password = applyMd5Encoding(clearTextPassword);
-		User user = getUserByUsername(username);
-		return md5Password.equals(user.getMd5password());
+	public void recordNewPassword(UserAccount userAccount,
+			String newClearTextPassword) {
+		newPasswords.put(userAccount.getEmailAddress(), newClearTextPassword);
 	}
 
 	@Override
-	public void recordNewPassword(String username, String newClearTextPassword) {
-		newPasswords.put(username, newClearTextPassword);
-	}
-
-	@Override
-	public void recordLoginAgainstUserAccount(String username,
+	public void recordLoginAgainstUserAccount(UserAccount userAccount,
 			AuthenticationSource authSource) {
-		recordedLogins.add(username);
+		recordedLogins.add(userAccount.getEmailAddress());
 
-		User user = getUserByUsername(username);
-		LoginStatusBean lsb = new LoginStatusBean(user.getURI(), authSource);
+		LoginStatusBean lsb = new LoginStatusBean(userAccount.getUri(),
+				authSource);
 		LoginStatusBean.setBean(request.getSession(), lsb);
 	}
 
@@ -167,16 +177,15 @@ public class AuthenticatorStub extends Authenticator {
 	}
 
 	@Override
-	public void recordLoginWithoutUserAccount(String username,
-			String individualUri, AuthenticationSource authSource) {
+	public boolean accountRequiresEditing(UserAccount userAccount) {
+		throw new RuntimeException(
+				"AuthenticatorStub.accountRequiresEditing() not implemented.");
+	}
+
+	@Override
+	public void recordLoginWithoutUserAccount(String individualUri) {
 		throw new RuntimeException(
 				"AuthenticatorStub.recordLoginWithoutUserAccount() not implemented.");
 	}
 
-	@Override
-	public boolean isPasswordChangeRequired(String username) {
-		throw new RuntimeException(
-				"AuthenticatorStub.isPasswordChangeRequired() not implemented.");
-	}
-
 }
diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/authenticate/ProgramLoginTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/authenticate/ProgramLoginTest.java
index 871ae5928..666b4b208 100644
--- a/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/authenticate/ProgramLoginTest.java
+++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/authenticate/ProgramLoginTest.java
@@ -2,15 +2,15 @@
 
 package edu.cornell.mannlib.vitro.webapp.controller.authenticate;
 
+import static edu.cornell.mannlib.vitro.webapp.controller.authenticate.ProgramLogin.ProgramLoginCore.PARAM_EMAIL_ADDRESS;
 import static edu.cornell.mannlib.vitro.webapp.controller.authenticate.ProgramLogin.ProgramLoginCore.PARAM_NEW_PASSWORD;
 import static edu.cornell.mannlib.vitro.webapp.controller.authenticate.ProgramLogin.ProgramLoginCore.PARAM_PASSWORD;
-import static edu.cornell.mannlib.vitro.webapp.controller.authenticate.ProgramLogin.ProgramLoginCore.PARAM_USERNAME;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
 import java.io.IOException;
 import java.net.URL;
-import java.util.Date;
+import java.util.Collections;
 
 import javax.servlet.ServletException;
 
@@ -27,7 +27,8 @@ import stubs.javax.servlet.http.HttpServletResponseStub;
 import stubs.javax.servlet.http.HttpSessionStub;
 import edu.cornell.mannlib.vedit.beans.LoginStatusBean;
 import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
-import edu.cornell.mannlib.vitro.webapp.beans.User;
+import edu.cornell.mannlib.vitro.webapp.auth.permissions.PermissionSetsLoader;
+import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
 
 /**
  * Test the basic features of ProgramTest.
@@ -38,13 +39,13 @@ public class ProgramLoginTest extends AbstractTestClass {
 	private static final String NEW_USER_URI = "new_user_uri";
 	private static final String NEW_USER_NAME = "new_user";
 	private static final String NEW_USER_PASSWORD = "new_user_pw";
-	private static final User NEW_USER = createUser(NEW_USER_URI,
+	private static final UserAccount NEW_USER = createUserAccount(NEW_USER_URI,
 			NEW_USER_NAME, NEW_USER_PASSWORD, 0);
 
 	private static final String OLD_USER_URI = "old_user_uri";
 	private static final String OLD_USER_NAME = "old_user";
 	private static final String OLD_USER_PASSWORD = "old_user_pw";
-	private static final User OLD_USER = createUser(OLD_USER_URI,
+	private static final UserAccount OLD_USER = createUserAccount(OLD_USER_URI,
 			OLD_USER_NAME, OLD_USER_PASSWORD, 10);
 
 	private AuthenticatorStub authenticator;
@@ -57,7 +58,8 @@ public class ProgramLoginTest extends AbstractTestClass {
 
 	@Before
 	public void setLogging() {
-//		setLoggerLevel(this.getClass(), Level.DEBUG);
+		// setLoggerLevel(this.getClass(), Level.DEBUG);
+		// setLoggerLevel(ProgramLogin.class, Level.DEBUG);
 	}
 
 	@Before
@@ -85,17 +87,16 @@ public class ProgramLoginTest extends AbstractTestClass {
 		response = new HttpServletResponseStub();
 	}
 
-	private static User createUser(String uri, String name, String password,
-			int loginCount) {
-		User user = new User();
-		user.setUsername(name);
-		user.setURI(uri);
-		user.setRoleURI(String.valueOf(50));
-		user.setMd5password(Authenticator.applyMd5Encoding(password));
+	private static UserAccount createUserAccount(String uri, String name,
+			String password, int loginCount) {
+		UserAccount user = new UserAccount();
+		user.setEmailAddress(name);
+		user.setUri(uri);
+		user.setPermissionSetUris(Collections
+				.singleton(PermissionSetsLoader.URI_DBA));
+		user.setMd5Password(Authenticator.applyMd5Encoding(password));
 		user.setLoginCount(loginCount);
-		if (loginCount > 0) {
-			user.setFirstTime(new Date(0));
-		}
+		user.setPasswordChangeRequired(loginCount == 0);
 		return user;
 	}
 
@@ -170,10 +171,10 @@ public class ProgramLoginTest extends AbstractTestClass {
 	// Helper methods
 	// ----------------------------------------------------------------------
 
-	private void executeRequest(String username, String password,
+	private void executeRequest(String email, String password,
 			String newPassword) {
-		if (username != null) {
-			request.addParameter(PARAM_USERNAME, username);
+		if (email != null) {
+			request.addParameter(PARAM_EMAIL_ADDRESS, email);
 		}
 		if (password != null) {
 			request.addParameter(PARAM_PASSWORD, password);
diff --git a/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/edit/AuthenticateTest.java b/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/edit/AuthenticateTest.java
index 624ca632f..80042b241 100644
--- a/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/edit/AuthenticateTest.java
+++ b/webapp/test/edu/cornell/mannlib/vitro/webapp/controller/edit/AuthenticateTest.java
@@ -2,6 +2,8 @@
 
 package edu.cornell.mannlib.vitro.webapp.controller.edit;
 
+import static edu.cornell.mannlib.vitro.webapp.auth.permissions.PermissionSetsLoader.URI_DBA;
+import static edu.cornell.mannlib.vitro.webapp.auth.permissions.PermissionSetsLoader.URI_SELF_EDITOR;
 import static edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean.State.FORCED_PASSWORD_CHANGE;
 import static edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean.State.LOGGING_IN;
 import static org.junit.Assert.assertEquals;
@@ -10,7 +12,7 @@ import static org.junit.Assert.fail;
 
 import java.net.URL;
 import java.util.Arrays;
-import java.util.Date;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -20,7 +22,7 @@ import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 
-import stubs.edu.cornell.mannlib.vitro.webapp.dao.UserDaoStub;
+import stubs.edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDaoStub;
 import stubs.edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactoryStub;
 import stubs.javax.servlet.ServletConfigStub;
 import stubs.javax.servlet.ServletContextStub;
@@ -30,7 +32,7 @@ import stubs.javax.servlet.http.HttpSessionStub;
 import edu.cornell.mannlib.vedit.beans.LoginStatusBean;
 import edu.cornell.mannlib.vedit.beans.LoginStatusBean.AuthenticationSource;
 import edu.cornell.mannlib.vitro.testing.AbstractTestClass;
-import edu.cornell.mannlib.vitro.webapp.beans.User;
+import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
 import edu.cornell.mannlib.vitro.webapp.controller.authenticate.Authenticator;
 import edu.cornell.mannlib.vitro.webapp.controller.authenticate.AuthenticatorStub;
 import edu.cornell.mannlib.vitro.webapp.controller.login.LoginProcessBean;
@@ -43,7 +45,7 @@ public class AuthenticateTest extends AbstractTestClass {
 	private AuthenticatorStub authenticator;
 	private ServletContextStub servletContext;
 	private WebappDaoFactoryStub webappDaoFactory;
-	private UserDaoStub userDao;
+	private UserAccountsDaoStub userAccountsDao;
 	private ServletConfigStub servletConfig;
 	private HttpSessionStub session;
 	private HttpServletRequestStub request;
@@ -59,27 +61,27 @@ public class AuthenticateTest extends AbstractTestClass {
 	private static final String NEW_DBA_NAME = "new_dba_name";
 	private static final String NEW_DBA_PW = "new_dba_pw";
 	private static final UserInfo NEW_DBA = new UserInfo(NEW_DBA_NAME,
-			"new_dba_uri", NEW_DBA_PW, 50, 0);
+			"new_dba_uri", NEW_DBA_PW, URI_DBA, 0);
 
 	/** A DBA who has logged in before. */
 	private static final String OLD_DBA_NAME = "old_dba_name";
 	private static final String OLD_DBA_PW = "old_dba_pw";
 	private static final String OLD_DBA_URI = "old_dba_uri";
-	private static final int OLD_DBA_SECURITY_LEVEL = 50;
 	private static final UserInfo OLD_DBA = new UserInfo(OLD_DBA_NAME,
-			OLD_DBA_URI, OLD_DBA_PW, OLD_DBA_SECURITY_LEVEL, 5);
+			OLD_DBA_URI, OLD_DBA_PW, URI_DBA, 5);
 
 	/** A self-editor who has logged in before and has a profile. */
 	private static final String OLD_SELF_NAME = "old_self_name";
 	private static final String OLD_SELF_PW = "old_self_pw";
 	private static final UserInfo OLD_SELF = new UserInfo(OLD_SELF_NAME,
-			"old_self_uri", OLD_SELF_PW, 1, 100);
+			"old_self_uri", OLD_SELF_PW, URI_SELF_EDITOR, 100);
 
 	/** A self-editor who has logged in before but has no profile. */
 	private static final String OLD_STRANGER_NAME = "old_stranger_name";
 	private static final String OLD_STRANGER_PW = "stranger_pw";
 	private static final UserInfo OLD_STRANGER = new UserInfo(
-			OLD_STRANGER_NAME, "old_stranger_uri", OLD_STRANGER_PW, 1, 20);
+			OLD_STRANGER_NAME, "old_stranger_uri", OLD_STRANGER_PW,
+			URI_SELF_EDITOR, 20);
 
 	/** the login page */
 	private static final String URL_LOGIN = "/vivo/login";
@@ -114,14 +116,14 @@ public class AuthenticateTest extends AbstractTestClass {
 		authenticator.setAssociatedUri(OLD_SELF.username,
 				"old_self_associated_uri");
 
-		userDao = new UserDaoStub();
-		userDao.addUser(createUserFromUserInfo(NEW_DBA));
-		userDao.addUser(createUserFromUserInfo(OLD_DBA));
-		userDao.addUser(createUserFromUserInfo(OLD_SELF));
-		userDao.addUser(createUserFromUserInfo(OLD_STRANGER));
+		userAccountsDao = new UserAccountsDaoStub();
+		userAccountsDao.addUser(createUserFromUserInfo(NEW_DBA));
+		userAccountsDao.addUser(createUserFromUserInfo(OLD_DBA));
+		userAccountsDao.addUser(createUserFromUserInfo(OLD_SELF));
+		userAccountsDao.addUser(createUserFromUserInfo(OLD_STRANGER));
 
 		webappDaoFactory = new WebappDaoFactoryStub();
-		webappDaoFactory.setUserDao(userDao);
+		webappDaoFactory.setUserAccountsDao(userAccountsDao);
 
 		servletContext = new ServletContextStub();
 		servletContext.setAttribute("webappDaoFactory", webappDaoFactory);
@@ -143,16 +145,14 @@ public class AuthenticateTest extends AbstractTestClass {
 		auth.init(servletConfig);
 	}
 
-	private User createUserFromUserInfo(UserInfo userInfo) {
-		User user = new User();
-		user.setUsername(userInfo.username);
-		user.setURI(userInfo.uri);
-		user.setRoleURI(String.valueOf(userInfo.securityLevel));
-		user.setMd5password(Authenticator.applyMd5Encoding(userInfo.password));
+	private UserAccount createUserFromUserInfo(UserInfo userInfo) {
+		UserAccount user = new UserAccount();
+		user.setEmailAddress(userInfo.username);
+		user.setUri(userInfo.uri);
+		user.setPermissionSetUris(userInfo.permissionSetUris);
+		user.setMd5Password(Authenticator.applyMd5Encoding(userInfo.password));
 		user.setLoginCount(userInfo.loginCount);
-		if (userInfo.loginCount > 0) {
-			user.setFirstTime(new Date(0));
-		}
+		user.setPasswordChangeRequired(userInfo.loginCount == 0);
 		return user;
 	}
 
@@ -617,23 +617,23 @@ public class AuthenticateTest extends AbstractTestClass {
 		final String username;
 		final String uri;
 		final String password;
-		final int securityLevel;
+		final Set permissionSetUris;
 		final int loginCount;
 
 		public UserInfo(String username, String uri, String password,
-				int securityLevel, int loginCount) {
+				String roleUri, int loginCount) {
 			this.username = username;
 			this.uri = uri;
 			this.password = password;
-			this.securityLevel = securityLevel;
+			this.permissionSetUris = Collections.singleton(roleUri);
 			this.loginCount = loginCount;
 		}
 
 		@Override
 		public String toString() {
 			return "UserInfo[username=" + username + ", uri=" + uri
-					+ ", password=" + password + ", securityLevel="
-					+ securityLevel + ", loginCount=" + loginCount + "]";
+					+ ", password=" + password + ", roleUri="
+					+ permissionSetUris + ", loginCount=" + loginCount + "]";
 		}
 	}
 
diff --git a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/UserAccountsDaoStub.java b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/UserAccountsDaoStub.java
new file mode 100644
index 000000000..811de33c3
--- /dev/null
+++ b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/UserAccountsDaoStub.java
@@ -0,0 +1,87 @@
+/* $This file is distributed under the terms of the license in /doc/license.txt$ */
+
+package stubs.edu.cornell.mannlib.vitro.webapp.dao;
+
+import java.util.Collection;
+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.PermissionSet;
+import edu.cornell.mannlib.vitro.webapp.beans.UserAccount;
+import edu.cornell.mannlib.vitro.webapp.dao.UserAccountsDao;
+
+/**
+ * TODO
+ */
+public class UserAccountsDaoStub implements UserAccountsDao {
+	private static final Log log = LogFactory.getLog(UserAccountsDaoStub.class);
+
+	private final Map userAccountsByUri = new HashMap();
+
+	// ----------------------------------------------------------------------
+	// Stub infrastructure
+	// ----------------------------------------------------------------------
+
+	public void addUser(UserAccount user) {
+		userAccountsByUri.put(user.getUri(), user);
+	}
+
+	// ----------------------------------------------------------------------
+	// Stub methods
+	// ----------------------------------------------------------------------
+
+	@Override
+	public UserAccount getUserAccountByUri(String uri) {
+		return userAccountsByUri.get(uri);
+	}
+
+	// ----------------------------------------------------------------------
+	// Un-implemented methods
+	// ----------------------------------------------------------------------
+
+	@Override
+	public UserAccount getUserAccountByEmail(String emailAddress) {
+		throw new RuntimeException(
+				"UserAccountsDaoStub.getUserAccountByEmail() not implemented.");
+	}
+
+	@Override
+	public String insertUserAccount(UserAccount userAccount) {
+		throw new RuntimeException(
+				"UserAccountsDaoStub.insertUserAccount() not implemented.");
+	}
+
+	@Override
+	public void updateUserAccount(UserAccount userAccount) {
+		throw new RuntimeException(
+				"UserAccountsDaoStub.updateUserAccount() not implemented.");
+	}
+
+	@Override
+	public void deleteUserAccount(String userAccountUri) {
+		throw new RuntimeException(
+				"UserAccountsDaoStub.deleteUserAccount() not implemented.");
+	}
+
+	@Override
+	public PermissionSet getPermissionSetByUri(String uri) {
+		throw new RuntimeException(
+				"UserAccountsDaoStub.getPermissionSetByUri() not implemented.");
+	}
+
+	@Override
+	public Collection getAllPermissionSets() {
+		throw new RuntimeException(
+				"UserAccountsDaoStub.getAllPermissionSets() not implemented.");
+	}
+
+	@Override
+	public UserAccount getUserAccountByExternalAuthId(String externalAuthId) {
+		throw new RuntimeException(
+				"UserAccountsDao.getUserAccountByExternalAuthId() not implemented.");
+	}
+
+}
diff --git a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryStub.java b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryStub.java
index 13277aca5..5b3a76409 100644
--- a/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryStub.java
+++ b/webapp/test/stubs/edu/cornell/mannlib/vitro/webapp/dao/WebappDaoFactoryStub.java
@@ -45,6 +45,7 @@ public class WebappDaoFactoryStub implements WebappDaoFactory {
 	private IndividualDao individualDao;
 	private DataPropertyDao dataPropertyDao;
 	private ObjectPropertyDao objectPropertyDao;
+	private UserAccountsDao userAccountsDao;
 
 	public void setIndividualDao(IndividualDao individualDao) {
 		this.individualDao = individualDao;
@@ -58,10 +59,8 @@ public class WebappDaoFactoryStub implements WebappDaoFactory {
 		this.objectPropertyDao = objectPropertyDao;
 	}
 
-	// TODO This goes away when the UserAccounts stuff is fully implemented -- jb
-	private UserDao userDao;
-	public void setUserDao(UserDao userDao) {
-		this.userDao = userDao;
+	public void setUserAccountsDao(UserAccountsDao userAccountsDao) {
+		this.userAccountsDao = userAccountsDao;
 	}
 
 	// ----------------------------------------------------------------------
@@ -83,10 +82,9 @@ public class WebappDaoFactoryStub implements WebappDaoFactory {
 		return this.objectPropertyDao;
 	}
 
-    // TODO This goes away when the UserAccounts stuff is fully implemented -- jb
 	@Override
-	public UserDao getUserDao() {
-		return this.userDao;
+	public UserAccountsDao getUserAccountsDao() {
+		return this.userAccountsDao;
 	}
 
 	// ----------------------------------------------------------------------
@@ -225,12 +223,6 @@ public class WebappDaoFactoryStub implements WebappDaoFactory {
 				"WebappDaoFactory.getLinktypeDao() not implemented.");
 	}
 
-	@Override
-	public UserAccountsDao getUserAccountsDao() {
-		throw new RuntimeException(
-		"WebappDaoFactory.getUserAccountsDao() not implemented.");
-	}
-	
 	@Override
 	public VClassGroupDao getVClassGroupDao() {
 		throw new RuntimeException(
@@ -272,4 +264,9 @@ public class WebappDaoFactoryStub implements WebappDaoFactory {
 		throw new RuntimeException("WebappDaoFactory.close() not implemented.");
 	}
 
+	@Override
+	public UserDao getUserDao() {
+		throw new RuntimeException("WebappDaoFactory.getUserDao() not implemented.");
+	}
+
 }
diff --git a/webapp/web/templates/freemarker/body/admin/admin-showAuth.ftl b/webapp/web/templates/freemarker/body/admin/admin-showAuth.ftl
index e11bb519e..a8e39ff2d 100644
--- a/webapp/web/templates/freemarker/body/admin/admin-showAuth.ftl
+++ b/webapp/web/templates/freemarker/body/admin/admin-showAuth.ftl
@@ -10,12 +10,14 @@ ${stylesheets.add('
         
-            
+            
-            
+            
-            
+            <#list currentUser.permissionSetUris as role>
+                
+            
Current user
URI:${currentUser.URI}
URI:${currentUser.uri}
First name:${currentUser.firstName}
Last name:${currentUser.lastName}
Username:${currentUser.username}
Email:${currentUser.emailAddress}
Login count:${currentUser.loginCount}
Role:${currentUser.roleURI}
Role:${role}
<#else>

Not logged in

diff --git a/webapp/web/templates/freemarker/body/login/adminLogin.ftl b/webapp/web/templates/freemarker/body/login/adminLogin.ftl index 1751efd3f..6bf7228f2 100644 --- a/webapp/web/templates/freemarker/body/login/adminLogin.ftl +++ b/webapp/web/templates/freemarker/body/login/adminLogin.ftl @@ -5,7 +5,7 @@

Internal Login

- <#if errorNoUser??> + <#if errorNoEmail??> <#assign errorMessage = "No email supplied." /> @@ -52,11 +52,11 @@ - + <#else> - - + +