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.*;
public class LdapUserProvider implements UserProvider {
private LdapManager manager;
private Map<String, String> searchFields;
public LdapUserProvider() {
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 {
......@@ -215,6 +235,12 @@ public class LdapUserProvider implements UserProvider {
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 {
throw new UnsupportedOperationException();
}
......@@ -234,4 +260,60 @@ public class LdapUserProvider implements UserProvider {
public void setModificationDate(String username, Date modificationDate) throws UserNotFoundException {
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 {
"UPDATE jiveUser SET creationDate=? WHERE username=?";
private static final String UPDATE_MODIFICATION_DATE =
"UPDATE jiveUser SET modificationDate=? WHERE username=?";
private static final String LOAD_PASSWORD =
"SELECT password FROM jiveUser WHERE username=?";
private static final String UPDATE_PASSWORD =
"UPDATE jiveUser SET password=? WHERE username=?";
......@@ -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
{
Connection con = null;
......@@ -357,4 +383,57 @@ public class DefaultUserProvider implements UserProvider {
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 {
public Collection<User> getUsers(int startIndex, int 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 {
* @return the User.
* @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
......@@ -42,7 +42,7 @@ public interface UserProvider {
* @return a new User.
* @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;
/**
......@@ -52,7 +52,7 @@ public interface UserProvider {
*
* @param username the username to delete.
*/
void deleteUser(String username);
public void deleteUser(String username);
/**
* Returns the number of users in the system.
......@@ -89,6 +89,19 @@ public interface UserProvider {
*/
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
* if this operation is not supported by the backend user store.
......@@ -100,7 +113,7 @@ public interface UserProvider {
* support the operation (this is an optional operation).
*/
public void setPassword(String username, String password)
throws UserNotFoundException;
throws UserNotFoundException, UnsupportedOperationException;
/**
* Sets the user's name. This method should throw an UnsupportedOperationException
......@@ -143,6 +156,41 @@ public interface UserProvider {
* @param modificationDate the date the user was last modified.
* @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