Revamped session handling, deprecating the old "persist or not" scheme and

switching to one where the application tells us how many days the session
should last. Added a mechanism for checking whether a session is still valid
and refreshing it if so.


git-svn-id: https://samskivert.googlecode.com/svn/trunk@1990 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
mdb
2006-12-06 19:36:41 +00:00
parent 5e61ec0641
commit b1a1a31097
3 changed files with 161 additions and 185 deletions
@@ -37,13 +37,10 @@ public interface Authenticator
* repository against which the user-supplied data is to be checked. * repository against which the user-supplied data is to be checked.
* @param username the username supplied by the user. * @param username the username supplied by the user.
* @param password the plaintext password supplied by the user. * @param password the plaintext password supplied by the user.
* @param persist if true, the cookie will expire in one month, if
* false, the cookie will expire in 24 hours.
* *
* @throws AuthenticationFailedException if the user failed to pass * @throws AuthenticationFailedException if the user failed to pass
* the authentication check. * the authentication check.
*/ */
public void authenticateUser ( public void authenticateUser (User user, String username, Password password)
User user, String username, Password password, boolean persist)
throws AuthenticationFailedException; throws AuthenticationFailedException;
} }
@@ -36,9 +36,8 @@ import com.samskivert.util.StringUtil;
import com.samskivert.util.Tuple; import com.samskivert.util.Tuple;
/** /**
* The user manager provides easy access to user objects for servlets. It * The user manager provides easy access to user objects for servlets. It takes care of cookie
* takes care of cookie management involved in login, logout and loading a * management involved in login, logout and loading a user record during an authenticated session.
* user record during an authenticated session.
*/ */
public class UserManager public class UserManager
{ {
@@ -51,16 +50,14 @@ public class UserManager
new PasswordAuthenticator(); new PasswordAuthenticator();
/** /**
* A totally insecure authenticator that authenticates any user. * A totally insecure authenticator that authenticates any user. <em>Note:</em> Applications
* <em>Note:</em> Applications that make use of this authenticator * that make use of this authenticator should make sure the user has already been authenticated
* should make sure the user has already been authenticated through * through some other means.
* some other means.
*/ */
public static class InsecureAuthenticator implements Authenticator public static class InsecureAuthenticator implements Authenticator
{ {
// documentation inherited // documentation inherited
public void authenticateUser ( public void authenticateUser (User user, String username, Password password)
User user, String username, Password password, boolean persist)
throws InvalidPasswordException throws InvalidPasswordException
{ {
// don't care // don't care
@@ -68,14 +65,13 @@ public class UserManager
} }
/** /**
* An authenticator that requires that the user-supplied password * An authenticator that requires that the user-supplied password match the actual user
* match the actual user password. * password.
*/ */
public static class PasswordAuthenticator implements Authenticator public static class PasswordAuthenticator implements Authenticator
{ {
// documentation inherited // documentation inherited
public void authenticateUser ( public void authenticateUser (User user, String username, Password password)
User user, String username, Password password, boolean persist)
throws AuthenticationFailedException throws AuthenticationFailedException
{ {
if (!user.passwordsMatch(password)) { if (!user.passwordsMatch(password)) {
@@ -85,27 +81,25 @@ public class UserManager
} }
/** /**
* Prepares this user manager it for operation. Presently the user manager * Prepares this user manager it for operation. Presently the user manager requires the
* requires the following configuration information: * following configuration information:
* *
* <ul> * <ul>
* <li><code>login_url</code>: Should be set to the URL to which to * <li><code>login_url</code>: Should be set to the URL to which to redirect a requester if
* redirect a requester if they are required to login before accessing * they are required to login before accessing the requested page. For example:
* the requested page. For example:
* *
* <pre> * <pre>
* login_url = /usermgmt/login.ajsp?return=%R * login_url = /usermgmt/login.ajsp?return=%R
* </pre> * </pre>
* *
* The <code>%R</code> will be replaced with the URL encoded URL the * The <code>%R</code> will be replaced with the URL encoded URL the user is currently
* user is currently requesting (complete with query parameters) so * requesting (complete with query parameters) so that the login code can redirect the user
* that the login code can redirect the user back to this request once * back to this request once they are authenticated.
* they are authenticated.
* </ul> * </ul>
* *
* @param config the user manager configuration properties. * @param config the user manager configuration properties.
* @param conprov the database connection provider that will be used * @param conprov the database connection provider that will be used to obtain a connection to
* to obtain a connection to the user database. * the user database.
*/ */
public void init (Properties config, ConnectionProvider conprov) public void init (Properties config, ConnectionProvider conprov)
throws PersistenceException throws PersistenceException
@@ -119,8 +113,7 @@ public class UserManager
// fetch the login URL from the properties // fetch the login URL from the properties
_loginURL = config.getProperty("login_url"); _loginURL = config.getProperty("login_url");
if (_loginURL == null) { if (_loginURL == null) {
Log.warning("No login_url supplied in user manager config. " + Log.warning("No login_url supplied in user manager config. Authentication won't work.");
"Authentication won't work.");
} }
// look up any override to our user auth cookie // look up any override to our user auth cookie
@@ -159,12 +152,11 @@ public class UserManager
} }
/** /**
* Fetches the necessary authentication information from the http * Fetches the necessary authentication information from the http request and loads the user
* request and loads the user identified by that information. * identified by that information.
* *
* @return the user associated with the request or null if no user was * @return the user associated with the request or null if no user was associated with the
* associated with the request or if the authentication information is * request or if the authentication information is bogus.
* bogus.
*/ */
public User loadUser (HttpServletRequest req) public User loadUser (HttpServletRequest req)
throws PersistenceException throws PersistenceException
@@ -182,11 +174,10 @@ public class UserManager
} }
/** /**
* Fetches the necessary authentication information from the http * Fetches the necessary authentication information from the http request and loads the user
* request and loads the user identified by that information. If no * identified by that information. If no user could be loaded (because the requester is not
* user could be loaded (because the requester is not authenticated), * authenticated), a redirect exception will be thrown to redirect the user to the login page
* a redirect exception will be thrown to redirect the user to the * specified in the user manager configuration.
* login page specified in the user manager configuration.
* *
* @return the user associated with the request. * @return the user associated with the request.
*/ */
@@ -206,29 +197,25 @@ public class UserManager
} }
/** /**
* Attempts to authenticate the requester and initiate an authenticated * Attempts to authenticate the requester and initiate an authenticated session for them. An
* session for them. An authenticated session involves their receiving a * authenticated session involves their receiving a cookie that proves them to be authenticated
* cookie that proves them to be authenticated and an entry in the session * and an entry in the session database being created that maps their information to their
* database being created that maps their information to their userid. If * userid. If this call completes, the session was established and the proper cookies were set
* this call completes, the session was established and the proper cookies * in the supplied response object. If invalid authentication information is provided or some
* were set in the supplied response object. If invalid authentication * other error occurs, an exception will be thrown.
* information is provided or some other error occurs, an exception will be
* thrown.
* *
* @param username The username supplied by the user. * @param username The username supplied by the user.
* @param password The password supplied by the user. * @param password The password supplied by the user.
* @param persist If true, the cookie will expire in one month, if false, * @param persist If true, the cookie will expire in one month, if false, the cookie will
* the cookie will expire at the end of the user's browser session. * expire at the end of the user's browser session.
* @param req The request via which the login page was loaded. * @param req The request via which the login page was loaded.
* @param rsp The response in which the cookie is to be set. * @param rsp The response in which the cookie is to be set.
* @param auth The authenticator used to check whether the user should be * @param auth The authenticator used to check whether the user should be authenticated.
* authenticated.
* *
* @return the user object of the authenticated user. * @return the user object of the authenticated user.
*/ */
public User login (String username, Password password, boolean persist, public User login (String username, Password password, boolean persist,
HttpServletRequest req, HttpServletResponse rsp, HttpServletRequest req, HttpServletResponse rsp, Authenticator auth)
Authenticator auth)
throws PersistenceException, AuthenticationFailedException throws PersistenceException, AuthenticationFailedException
{ {
// load up the requested user // load up the requested user
@@ -245,31 +232,29 @@ public class UserManager
} }
// run the user through the authentication gamut // run the user through the authentication gamut
auth.authenticateUser(user, username, password, persist); auth.authenticateUser(user, username, password);
// give them the necessary cookies and business // give them the necessary cookies and business
effectLogin(user, persist, req, rsp); effectLogin(user, persist ? PERSIST_EXPIRE_DAYS : NON_PERSIST_EXPIRE_DAYS, req, rsp);
return user; return user;
} }
/** /**
* Attempts to authenticate the requester and initiate an authenticated * Attempts to authenticate the requester and initiate an authenticated session for them. A
* session for them. A session token will be assigned to the user and * session token will be assigned to the user and returned along with the associated {@link
* returned along with the associated {@link User} record. It is assumed * User} record. It is assumed that the client will maintain the session token via its own
* that the client will maintain the session token via its own means. * means.
* *
* @param username The username supplied by the user. * @param username the username supplied by the user.
* @param password The password supplied by the user. * @param password the password supplied by the user.
* @param persist If true, the cookie will expire in one month, if false, * @param expires the number of days in which this session should expire.
* the cookie will expire at the end of the user's browser session. * @param auth the authenticator used to check whether the user should be authenticated.
* @param auth The authenticator used to check whether the user should be
* authenticated.
* *
* @return the user object of the authenticated user. * @return the user object of the authenticated user.
*/ */
public Tuple<User,String> login (String username, Password password, public Tuple<User,String> login (
boolean persist, Authenticator auth) String username, Password password, int expires, Authenticator auth)
throws PersistenceException, AuthenticationFailedException throws PersistenceException, AuthenticationFailedException
{ {
// load up the requested user // load up the requested user
@@ -286,37 +271,33 @@ public class UserManager
} }
// run the user through the authentication gamut // run the user through the authentication gamut
auth.authenticateUser(user, username, password, persist); auth.authenticateUser(user, username, password);
// register a session for this user // register a session for this user
String authcode = _repository.registerSession(user, persist); String authcode = _repository.registerSession(user, expires);
return new Tuple<User,String>(user, authcode); return new Tuple<User,String>(user, authcode);
} }
/** /**
* If a user is already known to be authenticated for one reason or * If a user is already known to be authenticated for one reason or other, this method can be
* other, this method can be used to give them the appropriate * used to give them the appropriate authentication cookies to effect their login.
* authentication cookies to effect their login. *
* @param expires the number of days in which to expire the session cookie, 0 means expire at
* the end of the browser session.
*/ */
public void effectLogin (User user, boolean persist, public void effectLogin (
HttpServletRequest req, HttpServletResponse rsp) User user, int expires, HttpServletRequest req, HttpServletResponse rsp)
throws PersistenceException throws PersistenceException
{ {
// register a session for this user String authcode = _repository.registerSession(user, Math.max(expires, 1));
String authcode = _repository.registerSession(user, persist);
// stick it into a cookie for their browsing convenience
Cookie acookie = new Cookie(_userAuthCookie, authcode); Cookie acookie = new Cookie(_userAuthCookie, authcode);
// strip the hostname from the server and use that as the domain // strip the hostname from the server and use that as the domain unless configured not to
// unless configured not to if (!"false".equalsIgnoreCase(_config.getProperty("auth_cookie.strip_hostname"))) {
if (!"false".equalsIgnoreCase(
_config.getProperty("auth_cookie.strip_hostname"))) {
CookieUtil.widenDomain(req, acookie); CookieUtil.widenDomain(req, acookie);
} }
acookie.setPath("/"); acookie.setPath("/");
// expire in one month if persistent, else at the end of the acookie.setMaxAge((expires > 0) ? (expires*24*60*60) : -1);
// session
acookie.setMaxAge((persist) ? (30*24*60*60) : -1);
rsp.addCookie(acookie); rsp.addCookie(acookie);
} }
@@ -378,4 +359,10 @@ public class UserManager
/** Prune the session table every hour. */ /** Prune the session table every hour. */
protected static final long SESSION_PRUNE_INTERVAL = 60L * 60L * 1000L; protected static final long SESSION_PRUNE_INTERVAL = 60L * 60L * 1000L;
/** Indicates how long (in days) that a "persisting" session token should last. */
protected static final int PERSIST_EXPIRE_DAYS = 30;
/** Indicates how long (in days) that a "non-persisting" session token should last. */
protected static final int NON_PERSIST_EXPIRE_DAYS = 1;
} }
@@ -47,24 +47,21 @@ import com.samskivert.util.Tuple;
import com.samskivert.servlet.SiteIdentifier; import com.samskivert.servlet.SiteIdentifier;
/** /**
* Interfaces with the RDBMS in which the user information is stored. The * Interfaces with the RDBMS in which the user information is stored. The user repository
* user repository encapsulates the creating, loading and management of * encapsulates the creating, loading and management of users and sessions.
* users and sessions.
*/ */
public class UserRepository extends JORARepository public class UserRepository extends JORARepository
{ {
/** /**
* The database identifier used to obtain a connection from our * The database identifier used to obtain a connection from our connection provider. The value
* connection provider. The value is <code>userdb</code> which you'll * is <code>userdb</code> which you'll probably need to know to provide the proper
* probably need to know to provide the proper configuration to your * configuration to your connection provider.
* connection provider.
*/ */
public static final String USER_REPOSITORY_IDENT = "userdb"; public static final String USER_REPOSITORY_IDENT = "userdb";
/** /**
* Creates the repository and opens the user database. The database * Creates the repository and opens the user database. The database identifier used to fetch
* identifier used to fetch our database connection is documented by * our database connection is documented by {@link #USER_REPOSITORY_IDENT}.
* {@link #USER_REPOSITORY_IDENT}.
* *
* @param provider the database connection provider. * @param provider the database connection provider.
*/ */
@@ -81,16 +78,15 @@ public class UserRepository extends JORARepository
* @param password the password for the new user. * @param password the password for the new user.
* @param realname the user's real name. * @param realname the user's real name.
* @param email the user's email address. * @param email the user's email address.
* @param siteId the unique identifier of the site through which this * @param siteId the unique identifier of the site through which this account is being
* account is being created. The resulting user will be tracked as * created. The resulting user will be tracked as originating from this site for accounting
* originating from this site for accounting purposes ({@link * purposes ({@link SiteIdentifier#DEFAULT_SITE_ID} can be used by systems that don't desire to
* SiteIdentifier#DEFAULT_SITE_ID} can be used by systems that don't * perform site tracking.
* desire to perform site tracking.
* *
* @return The userid of the newly created user. * @return The userid of the newly created user.
*/ */
public int createUser (Username username, Password password, public int createUser (
String realname, String email, int siteId) Username username, Password password, String realname, String email, int siteId)
throws UserExistsException, PersistenceException throws UserExistsException, PersistenceException
{ {
// create a new user object... // create a new user object...
@@ -106,8 +102,7 @@ public class UserRepository extends JORARepository
/** /**
* Looks up a user by username. * Looks up a user by username.
* *
* @return the user with the specified user id or null if no user with * @return the user with the specified user id or null if no user with that id exists.
* that id exists.
*/ */
public User loadUser (String username) public User loadUser (String username)
throws PersistenceException throws PersistenceException
@@ -118,8 +113,7 @@ public class UserRepository extends JORARepository
/** /**
* Looks up a user by userid. * Looks up a user by userid.
* *
* @return the user with the specified user id or null if no user with * @return the user with the specified user id or null if no user with that id exists.
* that id exists.
*/ */
public User loadUser (int userId) public User loadUser (int userId)
throws PersistenceException throws PersistenceException
@@ -130,15 +124,14 @@ public class UserRepository extends JORARepository
/** /**
* Looks up a user by a session identifier. * Looks up a user by a session identifier.
* *
* @return the user associated with the specified session or null of * @return the user associated with the specified session or null of no session exists with the
* no session exists with the supplied identifier. * supplied identifier.
*/ */
public User loadUserBySession (String sessionKey) public User loadUserBySession (String sessionKey)
throws PersistenceException throws PersistenceException
{ {
User user = load(_utable, "sessions", User user = load(_utable, "sessions", "where authcode = '" + sessionKey + "' " +
"where authcode = '" + sessionKey + "' AND " + "AND sessions.userId = users.userId");
"sessions.userId = users.userId");
if (user != null) { if (user != null) {
user.setDirtyMask(_utable.getFieldMask()); user.setDirtyMask(_utable.getFieldMask());
} }
@@ -165,12 +158,10 @@ public class UserRepository extends JORARepository
} }
/** /**
* Lookup a user by email address, something that is not efficient and * Lookup a user by email address, something that is not efficient and should really only be
* should really only be done by site admins attempting to look up a * done by site admins attempting to look up a user record.
* user record.
* *
* @return the user with the specified user id or null if no user with * @return the user with the specified user id or null if no user with that id exists.
* that id exists.
*/ */
public ArrayList<User> lookupUsersByEmail (String email) public ArrayList<User> lookupUsersByEmail (String email)
throws PersistenceException throws PersistenceException
@@ -179,12 +170,11 @@ public class UserRepository extends JORARepository
} }
/** /**
* Looks up a list of users that match an arbitrary query. Care should be * Looks up a list of users that match an arbitrary query. Care should be taken in constructing
* taken in constructing these queries as the user table is likely to be * these queries as the user table is likely to be large and a query that does not make use of
* large and a query that does not make use of indices could be very slow. * indices could be very slow.
* *
* @return the users matching the specified query or an empty list if there * @return the users matching the specified query or an empty list if there are no matches.
* are no matches.
*/ */
public ArrayList<User> lookupUsersWhere (final String where) public ArrayList<User> lookupUsersWhere (final String where)
throws PersistenceException throws PersistenceException
@@ -198,13 +188,12 @@ public class UserRepository extends JORARepository
} }
/** /**
* Updates a user that was previously fetched from the repository. * Updates a user that was previously fetched from the repository. Only fields that have been
* Only fields that have been modified since it was loaded will be * modified since it was loaded will be written to the database and those fields will
* written to the database and those fields will subsequently be * subsequently be marked clean once again.
* marked clean once again.
* *
* @return true if the record was updated, false if the update was * @return true if the record was updated, false if the update was skipped because no fields in
* skipped because no fields in the user record were modified. * the user record were modified.
*/ */
public boolean updateUser (final User user) public boolean updateUser (final User user)
throws PersistenceException throws PersistenceException
@@ -218,19 +207,16 @@ public class UserRepository extends JORARepository
} }
/** /**
* 'Delete' the users account such that they can no longer access it, * 'Delete' the users account such that they can no longer access it, however we do not delete
* however we do not delete the record from the db. The name is * the record from the db. The name is changed such that the original name has XX=FOO if the
* changed such that the original name has XX=FOO if the name were FOO * name were FOO originally. If we have to lop off any of the name to get our prefix to fit we
* originally. If we have to lop off any of the name to get our * use a minus sign instead of a equals side. The password field is set to be the empty string
* prefix to fit we use a minus sign instead of a equals side. The * so that no one can log in (since nothing hashes to the empty string. We also make sure
* password field is set to be the empty string so that no one can log * their email address no longer works, so in case we don't ignore 'deleted' users when we do
* in (since nothing hashes to the empty string. We also make sure * the sql to get emailaddresses for the mass mailings we still won't spam delete folk. We
* their email address no longer works, so in case we don't ignore * leave the emailaddress intact exect for the @ sign which gets turned to a #, so that we can
* 'deleted' users when we do the sql to get emailaddresses for the mass * see what their email was incase it was an accidently deletion and we have to verify through
* mailings we still won't spam delete folk. We leave the emailaddress * email.
* intact exect for the @ sign which gets turned to a #, so that we can
* see what their email was incase it was an accidently deletion and we
* have to verify through email.
*/ */
public void deleteUser (final User user) public void deleteUser (final User user)
throws PersistenceException throws PersistenceException
@@ -259,8 +245,7 @@ public class UserRepository extends JORARepository
String oldName = user.username; String oldName = user.username;
for (int ii = 0; ii < 100; ii++) { for (int ii = 0; ii < 100; ii++) {
try { try {
user.username = StringUtil.truncate( user.username = StringUtil.truncate(ii + "=" + oldName, 24);
ii + "=" + oldName, 24);
_utable.update(conn, user, mask); _utable.update(conn, user, mask);
return null; // nothing to return return null; // nothing to return
} catch (SQLException se) { } catch (SQLException se) {
@@ -277,38 +262,27 @@ public class UserRepository extends JORARepository
} }
/** /**
* Creates a new session for the specified user and returns the randomly * Creates a new session for the specified user and returns the randomly generated session
* generated session identifier for that session. If a session entry * identifier for that session. If a session entry already exists for the specified user it
* already exists for the specified user it will be reused. * will be reused.
* *
* <p> Temporary sessions are set to expire in two days (the assumption is * @param expireDays the number of days in which the session token should expire.
* that the browser will be given a non-persistent cookie and we should
* prune the session table entry after some reasonable amount of time),
* persistent sessions expire after one month.
*/ */
public String registerSession (final User user, boolean persist) public String registerSession (User user, int expireDays)
throws PersistenceException throws PersistenceException
{ {
// figure out when to expire the session
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, persist ? 30 : 2);
final Date expires = new Date(cal.getTime().getTime());
// look for an existing session for this user // look for an existing session for this user
Tuple<Integer,String> session = execute( final String query = "select sessionId, authcode from sessions " +
new Operation<Tuple<Integer,String>>() { "where userId = " + user.userId;
public Tuple<Integer,String> invoke ( Tuple<Integer,String> session = execute(new Operation<Tuple<Integer,String>>() {
Connection conn, DatabaseLiaison liaison) public Tuple<Integer,String> invoke (Connection conn, DatabaseLiaison liaison)
throws PersistenceException, SQLException throws PersistenceException, SQLException
{ {
Statement stmt = conn.createStatement(); Statement stmt = conn.createStatement();
try { try {
String query = "select sessionId, authcode from sessions " +
"where userId = " + user.userId;
ResultSet rs = stmt.executeQuery(query); ResultSet rs = stmt.executeQuery(query);
while (rs.next()) { while (rs.next()) {
return new Tuple<Integer,String>( return new Tuple<Integer,String>(rs.getInt(1), rs.getString(2));
rs.getInt(1), rs.getString(2));
} }
return null; return null;
} finally { } finally {
@@ -317,6 +291,11 @@ public class UserRepository extends JORARepository
} }
}); });
// figure out when to expire the session
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, expireDays);
Date expires = new Date(cal.getTime().getTime());
// if we found one, update its expires time and reuse it // if we found one, update its expires time and reuse it
if (session != null) { if (session != null) {
update("update sessions set expires = '" + expires + "' " + update("update sessions set expires = '" + expires + "' " +
@@ -326,11 +305,29 @@ public class UserRepository extends JORARepository
// otherwise create a new one and insert it into the table // otherwise create a new one and insert it into the table
String authcode = UserUtil.genAuthCode(user); String authcode = UserUtil.genAuthCode(user);
update("insert into sessions (authcode, userId, expires) values('" + update("insert into sessions (authcode, userId, expires) values('" + authcode + "', " +
authcode + "', " + user.userId + ", '" + expires + "')"); user.userId + ", '" + expires + "')");
return authcode; return authcode;
} }
/**
* Validates that the supplied session key is still valid and if so, refreshes it for the
* specified number of days.
*
* @return true if the session was located and refreshed, false if it no longer exists.
*/
public boolean refreshSession (String sessionKey, int expireDays)
throws PersistenceException
{
Calendar cal = Calendar.getInstance();
cal.add(Calendar.DATE, expireDays);
Date expires = new Date(cal.getTime().getTime());
// attempt to update an existing session row, returning true if we found and updated it
return (update("update sessions set expires = '" + expires + "' " +
"where sessionId = " + sessionKey) == 1);
}
/** /**
* Prunes any expired sessions from the sessions table. * Prunes any expired sessions from the sessions table.
*/ */
@@ -341,9 +338,8 @@ public class UserRepository extends JORARepository
} }
/** /**
* Loads the usernames of the users identified by the supplied user * Loads the usernames of the users identified by the supplied user ids and returns them in an
* ids and returns them in an array. If any users do not exist, their * array. If any users do not exist, their slot in the array will contain a null.
* slot in the array will contain a null.
*/ */
public String[] loadUserNames (int[] userIds) public String[] loadUserNames (int[] userIds)
throws PersistenceException throws PersistenceException
@@ -352,9 +348,8 @@ public class UserRepository extends JORARepository
} }
/** /**
* Loads the real names of the users identified by the supplied user * Loads the real names of the users identified by the supplied user ids and returns them in an
* ids and returns them in an array. If any users do not exist, their * array. If any users do not exist, their slot in the array will contain a null.
* slot in the array will contain a null.
*/ */
public String[] loadRealNames (int[] userIds) public String[] loadRealNames (int[] userIds)
throws PersistenceException throws PersistenceException
@@ -397,12 +392,11 @@ public class UserRepository extends JORARepository
} }
/** /**
* Configures the supplied user record with the provided information * Configures the supplied user record with the provided information in preparation for
* in preparation for inserting the record into the database for the * inserting the record into the database for the first time.
* first time.
*/ */
protected void populateUser (User user, Username name, Password pass, protected void populateUser (
String realname, String email, int siteId) User user, Username name, Password pass, String realname, String email, int siteId)
{ {
user.username = name.getUsername(); user.username = name.getUsername();
user.setPassword(pass); user.setPassword(pass);
@@ -413,8 +407,8 @@ public class UserRepository extends JORARepository
} }
/** /**
* Inserts the supplied user record into the user database, assigning * Inserts the supplied user record into the user database, assigning it a userid in the
* it a userid in the process, which is returned. * process, which is returned.
*/ */
protected int insertUser (final User user) protected int insertUser (final User user)
throws UserExistsException, PersistenceException throws UserExistsException, PersistenceException
@@ -444,8 +438,8 @@ public class UserRepository extends JORARepository
} }
/** /**
* Loads up a user record that matches the specified where clause. Returns * Loads up a user record that matches the specified where clause. Returns null if no record
* null if no record matches. * matches.
*/ */
protected User loadUserWhere (String where) protected User loadUserWhere (String where)
throws PersistenceException throws PersistenceException
@@ -474,8 +468,7 @@ public class UserRepository extends JORARepository
{ {
Statement stmt = conn.createStatement(); Statement stmt = conn.createStatement();
try { try {
String query = "select userId, " + column + String query = "select userId, " + column + " from users " +
" from users " +
"where userId in (" + ids + ")"; "where userId in (" + ids + ")";
ResultSet rs = stmt.executeQuery(query); ResultSet rs = stmt.executeQuery(query);
while (rs.next()) { while (rs.next()) {
@@ -502,9 +495,8 @@ public class UserRepository extends JORARepository
} }
/** /**
* Take the passed in int array and create the a string suitable for using * Take the passed in int array and create the a string suitable for using in a SQL set query
* in a SQL set query (I.e., "select foo, from bar where userid in * (I.e., "select foo, from bar where userid in (genIdString(userIds))"; )
* (genIdString(userIds))"; )
*/ */
protected String genIdString (int[] userIds) protected String genIdString (int[] userIds)
{ {