Commit ff4b8b34 authored by Matt Tucker's avatar Matt Tucker Committed by matt

Added wildcard searching of users, but still needs testing (JM-122).


git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@1064 b35dd754-fafc-0310-a699-88a17e54d16e
parent 7895227e
...@@ -31,9 +31,29 @@ import java.util.*; ...@@ -31,9 +31,29 @@ import java.util.*;
public class LdapUserProvider implements UserProvider { public class LdapUserProvider implements UserProvider {
private LdapManager manager; private LdapManager manager;
private Map<String, String> searchFields;
public LdapUserProvider() { public LdapUserProvider() {
manager = LdapManager.getInstance(); manager = LdapManager.getInstance();
searchFields = new HashMap<String,String>();
String fieldList = JiveGlobals.getXMLProperty("ldap.searchFields");
// If the value isn't present, default to to username, name, and email.
if (fieldList == null) {
searchFields.put("Username", manager.getUsernameField());
searchFields.put("Name", manager.getNameField());
searchFields.put("Email", manager.getEmailField());
}
else {
try {
for (StringTokenizer i=new StringTokenizer(fieldList, ","); i.hasMoreTokens(); ) {
String[] field = i.nextToken().split("/");
searchFields.put(field[0], field[1]);
}
}
catch (Exception e) {
Log.error("Error parsing LDAP search fields: " + fieldList, e);
}
}
} }
public User loadUser(String username) throws UserNotFoundException { public User loadUser(String username) throws UserNotFoundException {
...@@ -215,6 +235,12 @@ public class LdapUserProvider implements UserProvider { ...@@ -215,6 +235,12 @@ public class LdapUserProvider implements UserProvider {
return new UserCollection((String[])usernames.toArray(new String[usernames.size()])); return new UserCollection((String[])usernames.toArray(new String[usernames.size()]));
} }
public String getPassword(String username) throws UserNotFoundException,
UnsupportedOperationException
{
throw new UnsupportedOperationException();
}
public void setPassword(String username, String password) throws UserNotFoundException { public void setPassword(String username, String password) throws UserNotFoundException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
...@@ -234,4 +260,60 @@ public class LdapUserProvider implements UserProvider { ...@@ -234,4 +260,60 @@ public class LdapUserProvider implements UserProvider {
public void setModificationDate(String username, Date modificationDate) throws UserNotFoundException { public void setModificationDate(String username, Date modificationDate) throws UserNotFoundException {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
public Collection<String> getSearchFields() throws UnsupportedOperationException {
return Collections.unmodifiableCollection(searchFields.keySet());
}
public Collection<User> findUsers(String field, String query)
throws UnsupportedOperationException
{
String searchAttribute = searchFields.get(field);
if (searchAttribute == null) {
throw new IllegalArgumentException("Search field " + field + " is invalid.");
}
List<String> usernames = new ArrayList<String>();
LdapContext ctx = null;
try {
ctx = manager.getContext();
// Sort on username field.
Control[] searchControl = new Control[]{
new SortControl(new String[]{manager.getUsernameField()}, Control.NONCRITICAL)
};
ctx.setRequestControls(searchControl);
// Search for the dn based on the username.
SearchControls constraints = new SearchControls();
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
constraints.setReturningAttributes(new String[] { manager.getUsernameField() });
String filter = "(" + searchAttribute + "=" + query + ")";
NamingEnumeration answer = ctx.search("", filter, constraints);
while (answer.hasMoreElements()) {
// Get the next userID.
usernames.add(
(String)((SearchResult)answer.next()).getAttributes().get(
manager.getUsernameField()).get()
);
}
// If client-side sorting is enabled, sort.
if (Boolean.valueOf(JiveGlobals.getXMLProperty(
"ldap.clientSideSorting")).booleanValue())
{
Collections.sort(usernames);
}
}
catch (Exception e) {
Log.error(e);
}
finally {
try {
if (ctx != null) {
ctx.setRequestControls(null);
ctx.close();
}
}
catch (Exception ignored) { }
}
return new UserCollection((String[])usernames.toArray(new String[usernames.size()]));
}
} }
\ No newline at end of file
...@@ -52,6 +52,8 @@ public class DefaultUserProvider implements UserProvider { ...@@ -52,6 +52,8 @@ public class DefaultUserProvider implements UserProvider {
"UPDATE jiveUser SET creationDate=? WHERE username=?"; "UPDATE jiveUser SET creationDate=? WHERE username=?";
private static final String UPDATE_MODIFICATION_DATE = private static final String UPDATE_MODIFICATION_DATE =
"UPDATE jiveUser SET modificationDate=? WHERE username=?"; "UPDATE jiveUser SET modificationDate=? WHERE username=?";
private static final String LOAD_PASSWORD =
"SELECT password FROM jiveUser WHERE username=?";
private static final String UPDATE_PASSWORD = private static final String UPDATE_PASSWORD =
"UPDATE jiveUser SET password=? WHERE username=?"; "UPDATE jiveUser SET password=? WHERE username=?";
...@@ -336,6 +338,30 @@ public class DefaultUserProvider implements UserProvider { ...@@ -336,6 +338,30 @@ public class DefaultUserProvider implements UserProvider {
} }
} }
public String getPassword(String username) throws UserNotFoundException {
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(LOAD_PASSWORD);
pstmt.setString(1, username);
ResultSet rs = pstmt.executeQuery();
if (!rs.next()) {
throw new UserNotFoundException(username);
}
return rs.getString(1);
}
catch (SQLException sqle) {
throw new UserNotFoundException(sqle);
}
finally {
try { if (pstmt != null) pstmt.close(); }
catch (Exception e) { Log.error(e); }
try { if (con != null) con.close(); }
catch (Exception e) { Log.error(e); }
}
}
public void setPassword(String username, String password) throws UserNotFoundException public void setPassword(String username, String password) throws UserNotFoundException
{ {
Connection con = null; Connection con = null;
...@@ -357,4 +383,57 @@ public class DefaultUserProvider implements UserProvider { ...@@ -357,4 +383,57 @@ public class DefaultUserProvider implements UserProvider {
catch (Exception e) { Log.error(e); } catch (Exception e) { Log.error(e); }
} }
} }
public Collection<String> getSearchFields() throws UnsupportedOperationException {
return Arrays.asList("Username", "Name", "Email");
}
public Collection<User> findUsers(String field, String query) throws UnsupportedOperationException {
if (!getSearchFields().contains(field)) {
throw new IllegalArgumentException("Search field " + field + " is invalid.");
}
// SQL LIKE queries don't map directly into a keyword/wildcard search like we want.
// Therefore, we do a best approximiation by replacing '*' with '%' and then
// surrounding the whole query with two '%'. This will return more data than desired,
// but is better than returning less data than desired.
query = "%" + query.replace('*', '%') + "%";
if (query.endsWith("%%")) {
query = query.substring(0, query.length()-1);
}
List<String> usernames = new ArrayList<String>(500);
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
if (field.equals("Username")) {
pstmt = con.prepareStatement("SELECT username FROM jiveUser WHERE username LIKE ?");
}
else if (field.equals("Name")) {
pstmt = con.prepareStatement("SELECT username FROM jiveUser WHERE name LIKE ?");
}
else {
pstmt = con.prepareStatement("SELECT username FROM jiveUser WHERE email LIKE ?");
}
pstmt.setString(1, query);
ResultSet rs = pstmt.executeQuery();
// Set the fetch size. This will prevent some JDBC drivers from trying
// to load the entire result set into memory.
DbConnectionManager.setFetchSize(rs, 500);
while (rs.next()) {
usernames.add(rs.getString(1));
}
rs.close();
}
catch (SQLException e) {
Log.error(e);
}
finally {
try { if (pstmt != null) { pstmt.close(); } }
catch (Exception e) { Log.error(e); }
try { if (con != null) { con.close(); } }
catch (Exception e) { Log.error(e); }
}
return new UserCollection((String[])usernames.toArray(new String[usernames.size()]));
}
} }
\ No newline at end of file
...@@ -176,4 +176,43 @@ public class UserManager { ...@@ -176,4 +176,43 @@ public class UserManager {
public Collection<User> getUsers(int startIndex, int numResults) { public Collection<User> getUsers(int startIndex, int numResults) {
return provider.getUsers(startIndex, numResults); return provider.getUsers(startIndex, numResults);
} }
/**
* Returns the set of fields that can be used for searching for users. Each field
* returned must support wild-card and keyword searching. For example, an
* implementation might send back the set {"Username", "Name", "Email"}. Any of
* those three fields can then be used in a search with the
* {@link #findUsers(String,String)} method.<p>
*
* This method should throw an UnsupportedOperationException if this
* operation is not supported by the backend user store.
*
* @return the valid search fields.
* @throws UnsupportedOperationException if the provider does not
* support the operation (this is an optional operation).
*/
public Collection<String> getSearchFields() throws UnsupportedOperationException {
return provider.getSearchFields();
}
/**
* Searches for users based on a field an query string. The field must be one
* of the values returned by {@link #getSearchFields()}. The query can include
* wildcards. For example, a search on the field "Name" with a query of "Ma*"
* might return user's with the name "Matt", "Martha" and "Madeline".<p>
*
* This method should throw an UnsupportedOperationException if this
* operation is not supported by the backend user store.
*
* @param field the field to search on.
* @param query the query string.
* @return a Collection of users that match the search.
* @throws UnsupportedOperationException if the provider does not
* support the operation (this is an optional operation).
*/
public Collection<User> findUsers(String field, String query)
throws UnsupportedOperationException
{
return provider.findUsers(field, query);
}
} }
\ No newline at end of file
...@@ -28,7 +28,7 @@ public interface UserProvider { ...@@ -28,7 +28,7 @@ public interface UserProvider {
* @return the User. * @return the User.
* @throws UserNotFoundException if the User could not be loaded. * @throws UserNotFoundException if the User could not be loaded.
*/ */
User loadUser(String username) throws UserNotFoundException; public User loadUser(String username) throws UserNotFoundException;
/** /**
* Creates a new user. This method should throw an * Creates a new user. This method should throw an
...@@ -42,7 +42,7 @@ public interface UserProvider { ...@@ -42,7 +42,7 @@ public interface UserProvider {
* @return a new User. * @return a new User.
* @throws UserAlreadyExistsException if the username is already in use. * @throws UserAlreadyExistsException if the username is already in use.
*/ */
User createUser(String username, String password, String name, String email) public User createUser(String username, String password, String name, String email)
throws UserAlreadyExistsException; throws UserAlreadyExistsException;
/** /**
...@@ -52,7 +52,7 @@ public interface UserProvider { ...@@ -52,7 +52,7 @@ public interface UserProvider {
* *
* @param username the username to delete. * @param username the username to delete.
*/ */
void deleteUser(String username); public void deleteUser(String username);
/** /**
* Returns the number of users in the system. * Returns the number of users in the system.
...@@ -89,6 +89,19 @@ public interface UserProvider { ...@@ -89,6 +89,19 @@ public interface UserProvider {
*/ */
public Collection<User> getUsers(int startIndex, int numResults); public Collection<User> getUsers(int startIndex, int numResults);
/**
* Returns the user's password. This method should throw an UnsupportedOperationException
* if this operation is not supported by the backend user store.
*
* @param username the username of the user.
* @return the user's password.
* @throws UserNotFoundException if the given user could not be loaded.
* @throws UnsupportedOperationException if the provider does not
* support the operation (this is an optional operation).
*/
public String getPassword(String username) throws UserNotFoundException,
UnsupportedOperationException;
/** /**
* Sets the users's password. This method should throw an UnsupportedOperationException * Sets the users's password. This method should throw an UnsupportedOperationException
* if this operation is not supported by the backend user store. * if this operation is not supported by the backend user store.
...@@ -100,7 +113,7 @@ public interface UserProvider { ...@@ -100,7 +113,7 @@ public interface UserProvider {
* support the operation (this is an optional operation). * support the operation (this is an optional operation).
*/ */
public void setPassword(String username, String password) public void setPassword(String username, String password)
throws UserNotFoundException; throws UserNotFoundException, UnsupportedOperationException;
/** /**
* Sets the user's name. This method should throw an UnsupportedOperationException * Sets the user's name. This method should throw an UnsupportedOperationException
...@@ -143,6 +156,41 @@ public interface UserProvider { ...@@ -143,6 +156,41 @@ public interface UserProvider {
* @param modificationDate the date the user was last modified. * @param modificationDate the date the user was last modified.
* @throws UserNotFoundException if the user could not be found. * @throws UserNotFoundException if the user could not be found.
*/ */
public void setModificationDate(String username, Date modificationDate) throws UserNotFoundException; public void setModificationDate(String username, Date modificationDate)
throws UserNotFoundException;
/**
* Returns the set of fields that can be used for searching for users. Each field
* returned must support wild-card and keyword searching. For example, an
* implementation might send back the set {"Username", "Name", "Email"}. Any of
* those three fields can then be used in a search with the
* {@link #findUsers(String,String)} method.<p>
*
* This method should throw an UnsupportedOperationException if this
* operation is not supported by the backend user store.
*
* @return the valid search fields.
* @throws UnsupportedOperationException if the provider does not
* support the operation (this is an optional operation).
*/
public Collection<String> getSearchFields() throws UnsupportedOperationException;
/**
* Searches for users based on a field an query string. The field must be one
* of the values returned by {@link #getSearchFields()}. The query can include
* wildcards. For example, a search on the field "Name" with a query of "Ma*"
* might return user's with the name "Matt", "Martha" and "Madeline".<p>
*
* This method should throw an UnsupportedOperationException if this
* operation is not supported by the backend user store.
*
* @param field the field to search on.
* @param query the query string.
* @return a Collection of users that match the search.
* @throws UnsupportedOperationException if the provider does not
* support the operation (this is an optional operation).
*/
public Collection<User> findUsers(String field, String query)
throws UnsupportedOperationException;
} }
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment