GUACAMOLE-1239: Update JDBC queries to handle case-sensitivity.

This commit is contained in:
Virtually Nick
2024-03-25 15:38:28 -04:00
parent 4d5101574a
commit 116f709454
38 changed files with 1210 additions and 241 deletions

View File

@@ -19,6 +19,7 @@
package org.apache.guacamole.auth.jdbc; package org.apache.guacamole.auth.jdbc;
import com.google.inject.Inject;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@@ -56,6 +57,12 @@ public class HistoryTrackingConnection extends DelegatingConnection {
*/ */
private final ConnectionRecordMapper connectionRecordMapper; private final ConnectionRecordMapper connectionRecordMapper;
/**
* The Guacamole server environment.
*/
@Inject
private JDBCEnvironment environment;
/** /**
* Creates a new HistoryConnection that wraps the given connection, * Creates a new HistoryConnection that wraps the given connection,
* automatically creating a history record when the connection is * automatically creating a history record when the connection is
@@ -98,7 +105,8 @@ public class HistoryTrackingConnection extends DelegatingConnection {
connectionRecordModel.setConnectionName(this.getDelegateConnection().getName()); connectionRecordModel.setConnectionName(this.getDelegateConnection().getName());
// Insert the connection history record to mark the start of this connection // Insert the connection history record to mark the start of this connection
connectionRecordMapper.insert(connectionRecordModel); connectionRecordMapper.insert(connectionRecordModel,
environment.getCaseSensitiveUsernames());
// Include history record UUID as token // Include history record UUID as token
ModeledConnectionRecord modeledRecord = new ModeledConnectionRecord(connectionRecordModel); ModeledConnectionRecord modeledRecord = new ModeledConnectionRecord(connectionRecordModel);

View File

@@ -272,17 +272,4 @@ public abstract class JDBCEnvironment extends DelegatingEnvironment {
} }
/**
* Returns a boolean value that indicates whether or not usernames should
* be treated as case-sensitive.
*
* @return
* true if usernames should be treated as case-sensitive, or false if
* usernames should be treated as case-insensitive.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public abstract boolean getCaseSensitiveUsernames() throws GuacamoleException;
} }

View File

@@ -39,10 +39,15 @@ public interface ActivityRecordMapper<ModelType> {
* @param record * @param record
* The activity record to insert. * The activity record to insert.
* *
* @param caseSensitive
* Whether or not string comparisons should be done in a case-sensitive
* manner.
*
* @return * @return
* The number of rows inserted. * The number of rows inserted.
*/ */
int insert(@Param("record") ModelType record); int insert(@Param("record") ModelType record,
@Param("caseSensitive") boolean caseSensitive);
/** /**
* Updates the given activity record in the database, assigning an end * Updates the given activity record in the database, assigning an end
@@ -86,6 +91,10 @@ public interface ActivityRecordMapper<ModelType> {
* @param limit * @param limit
* The maximum number of records that should be returned. * The maximum number of records that should be returned.
* *
* @param caseSensitive
* Whether or not string comparisons should be done in a case-sensitive
* manner.
*
* @return * @return
* The results of the search performed with the given parameters. * The results of the search performed with the given parameters.
*/ */
@@ -93,7 +102,8 @@ public interface ActivityRecordMapper<ModelType> {
@Param("recordIdentifier") String recordIdentifier, @Param("recordIdentifier") String recordIdentifier,
@Param("terms") Collection<ActivityRecordSearchTerm> terms, @Param("terms") Collection<ActivityRecordSearchTerm> terms,
@Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates, @Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
@Param("limit") int limit); @Param("limit") int limit,
@Param("caseSensitive") boolean caseSensitive);
/** /**
* Searches for up to <code>limit</code> activity records that contain * Searches for up to <code>limit</code> activity records that contain
@@ -133,6 +143,10 @@ public interface ActivityRecordMapper<ModelType> {
* no groups are given, only permissions directly granted to the user * no groups are given, only permissions directly granted to the user
* will be used. * will be used.
* *
* @param caseSensitive
* Whether or not string comparisons should be done in a case-sensitive
* manner.
*
* @return * @return
* The results of the search performed with the given parameters. * The results of the search performed with the given parameters.
*/ */
@@ -142,6 +156,7 @@ public interface ActivityRecordMapper<ModelType> {
@Param("terms") Collection<ActivityRecordSearchTerm> terms, @Param("terms") Collection<ActivityRecordSearchTerm> terms,
@Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates, @Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
@Param("limit") int limit, @Param("limit") int limit,
@Param("effectiveGroups") Collection<String> effectiveGroups); @Param("effectiveGroups") Collection<String> effectiveGroups,
@Param("caseSensitive") boolean caseSensitive);
} }

View File

@@ -28,19 +28,20 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.language.TranslatableGuacamoleClientOverrunException;
import org.apache.guacamole.language.TranslatableMessage;
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
import org.apache.guacamole.GuacamoleClientException; import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm; import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate; import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.auth.jdbc.base.ModeledChildDirectoryObjectService; import org.apache.guacamole.auth.jdbc.base.ModeledChildDirectoryObjectService;
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionMapper; import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionMapper;
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper; import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
import org.apache.guacamole.language.TranslatableGuacamoleClientOverrunException;
import org.apache.guacamole.language.TranslatableMessage;
import org.apache.guacamole.net.GuacamoleTunnel; import org.apache.guacamole.net.GuacamoleTunnel;
import org.apache.guacamole.net.auth.Connection; import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.ConnectionRecord; import org.apache.guacamole.net.auth.ConnectionRecord;
@@ -86,6 +87,12 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
@Inject @Inject
private Provider<ModeledConnection> connectionProvider; private Provider<ModeledConnection> connectionProvider;
/**
* The server environment for retrieving configuration.
*/
@Inject
private JDBCEnvironment environment;
/** /**
* Service for creating and tracking tunnels. * Service for creating and tracking tunnels.
*/ */
@@ -486,14 +493,16 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
// Bypass permission checks if the user is privileged or has System-level audit permissions // Bypass permission checks if the user is privileged or has System-level audit permissions
if (user.isPrivileged() || user.getUser().getEffectivePermissions().getSystemPermissions().hasPermission(SystemPermission.Type.AUDIT)) if (user.isPrivileged() || user.getUser().getEffectivePermissions().getSystemPermissions().hasPermission(SystemPermission.Type.AUDIT))
searchResults = connectionRecordMapper.search(identifier, searchResults = connectionRecordMapper.search(identifier,
recordIdentifier, requiredContents, sortPredicates, limit); recordIdentifier, requiredContents, sortPredicates, limit,
environment.getCaseSensitiveUsernames());
// Otherwise only return explicitly readable history records // Otherwise only return explicitly readable history records
else else
searchResults = connectionRecordMapper.searchReadable(identifier, searchResults = connectionRecordMapper.searchReadable(identifier,
user.getUser().getModel(), recordIdentifier, user.getUser().getModel(), recordIdentifier,
requiredContents, sortPredicates, limit, requiredContents, sortPredicates, limit,
user.getEffectiveUserGroups()); user.getEffectiveUserGroups(),
environment.getCaseSensitiveUsernames());
return getObjectInstances(searchResults); return getObjectInstances(searchResults);

View File

@@ -19,7 +19,142 @@
package org.apache.guacamole.auth.jdbc.permission; package org.apache.guacamole.auth.jdbc.permission;
import java.util.Collection;
import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.ibatis.annotations.Param;
/** /**
* Mapper for user permissions. * Mapper for user permissions.
*/ */
public interface UserPermissionMapper extends ObjectPermissionMapper {} public interface UserPermissionMapper extends ObjectPermissionMapper {
/**
* Deletes the given permissions from the database. If any permissions do
* not exist, they will be ignored.
*
* @param permissions
* The permissions to delete.
*
* @param caseSensitive
* Whether or not string comparisons for usernames will be done in a
* case-sensitive manner.
*
* @return
* The number of rows deleted.
*/
int delete(@Param("permissions") Collection<ObjectPermission.Type> permissions,
@Param("caseSensitive") boolean caseSensitive);
/**
* Inserts the given permissions into the database. If any permissions
* already exist, they will be ignored.
*
* @param permissions
* The permissions to insert.
*
* @param caseSensitive
* Whether or not string comparisons for usernames will be done in a
* case-sensitive manner.
*
* @return
* The number of rows inserted.
*/
int insert(@Param("permissions") Collection<ObjectPermission.Type> permissions,
@Param("caseSensitive") boolean caseSensitive);
/**
* Retrieves all permissions associated with the given entity (user or user
* group).
*
* @param entity
* The entity to retrieve permissions for.
*
* @param effectiveGroups
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the user. If
* no groups are given, only permissions directly granted to the user
* will be used.
*
* @param caseSensitive
* Whether or not string comparisons for usernames will be done in a
* case-sensitive manner.
*
* @return
* All permissions associated with the given entity.
*/
Collection<ObjectPermission.Type> select(@Param("entity") EntityModel entity,
@Param("effectiveGroups") Collection<String> effectiveGroups,
@Param("caseSensitive") boolean caseSensitive);
/**
* Retrieve the permission of the given type associated with the given
* entity and object, if it exists. If no such permission exists, null is
* returned.
*
* @param entity
* The entity to retrieve permissions for.
*
* @param type
* The type of permission to return.
*
* @param identifier
* The identifier of the object affected by the permission to return.
*
* @param effectiveGroups
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the user. If
* no groups are given, only permissions directly granted to the user
* will be used.
*
* @param caseSensitive
* Whether or not string comparisons for usernames will be done in a
* case-sensitive manner.
*
* @return
* The requested permission, or null if no such permission is granted
* to the given entity for the given object.
*/
ObjectPermissionModel selectOne(@Param("entity") EntityModel entity,
@Param("type") ObjectPermission.Type type,
@Param("identifier") String identifier,
@Param("effectiveGroups") Collection<String> effectiveGroups,
@Param("caseSensitive") boolean caseSensitive);
/**
* Retrieves the subset of the given identifiers for which the given entity
* has at least one of the given permissions.
*
* @param entity
* The entity to check permissions of.
*
* @param permissions
* The permissions to check. An identifier will be included in the
* resulting collection if at least one of these permissions is granted
* for the associated object
*
* @param identifiers
* The identifiers of the objects affected by the permissions being
* checked.
*
* @param effectiveGroups
* The identifiers of all groups that should be taken into account
* when determining the permissions effectively granted to the user. If
* no groups are given, only permissions directly granted to the user
* will be used.
*
* @param caseSensitive
* Whether or not string comparisons for usernames will be done in a
* case-sensitive manner.
*
* @return
* A collection containing the subset of identifiers for which at least
* one of the specified permissions is granted.
*/
Collection<String> selectAccessibleIdentifiers(@Param("entity") EntityModel entity,
@Param("permissions") Collection<ObjectPermission.Type> permissions,
@Param("identifiers") Collection<String> identifiers,
@Param("effectiveGroups") Collection<String> effectiveGroups,
@Param("caseSenstive") boolean caseSensitive);
}

View File

@@ -131,16 +131,21 @@ public class PasswordPolicyService {
* @return * @return
* true if the given password matches any of the user's previous * true if the given password matches any of the user's previous
* passwords, up to the specified limit, false otherwise. * passwords, up to the specified limit, false otherwise.
*
* @throws GuacamoleException
* If an error occurs accessing environment information used for
* retrieving configuration values.
*/ */
private boolean matchesPreviousPasswords(String password, String username, private boolean matchesPreviousPasswords(String password, String username,
int historySize) { int historySize) throws GuacamoleException {
// No need to compare if no history is relevant // No need to compare if no history is relevant
if (historySize <= 0) if (historySize <= 0)
return false; return false;
// Check password against all recorded hashes // Check password against all recorded hashes
List<PasswordRecordModel> history = passwordRecordMapper.select(username, historySize); List<PasswordRecordModel> history = passwordRecordMapper.select(username,
historySize, environment.getCaseSensitiveUsernames());
for (PasswordRecordModel record : history) { for (PasswordRecordModel record : history) {
byte[] hash = encryptionService.createPasswordHash(password, record.getPasswordSalt()); byte[] hash = encryptionService.createPasswordHash(password, record.getPasswordSalt());

View File

@@ -34,6 +34,7 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser; import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.auth.jdbc.connection.ModeledConnection; import org.apache.guacamole.auth.jdbc.connection.ModeledConnection;
import org.apache.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; import org.apache.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
@@ -168,6 +169,12 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
@Inject @Inject
private SharedConnectionMap connectionMap; private SharedConnectionMap connectionMap;
/**
* The Guacamole server environment.
*/
@Inject
private JDBCEnvironment environment;
/** /**
* All active connections through the tunnel having a given UUID. * All active connections through the tunnel having a given UUID.
*/ */
@@ -470,7 +477,9 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
// Record new active connection // Record new active connection
Runnable cleanupTask = new ConnectionCleanupTask(activeConnection); Runnable cleanupTask = new ConnectionCleanupTask(activeConnection);
try { try {
connectionRecordMapper.insert(activeConnection.getModel()); // This MUST happen before getUUID() is invoked, to ensure the ID driving the UUID exists // This MUST happen before getUUID() is invoked, to ensure the ID driving the UUID exists
connectionRecordMapper.insert(activeConnection.getModel(),
environment.getCaseSensitiveUsernames());
activeTunnels.put(activeConnection.getUUID().toString(), activeConnection); activeTunnels.put(activeConnection.getUUID().toString(), activeConnection);
} }

View File

@@ -795,6 +795,9 @@ public class ModeledUser extends ModeledPermissions<UserModel> implements User {
return environment.getCaseSensitiveUsernames(); return environment.getCaseSensitiveUsernames();
} }
catch (GuacamoleException e) { catch (GuacamoleException e) {
logger.error("Failed to retrieve the configuration for case-sensitive usernames: {}."
+ " Usernames comparisons will be case-sensitive.", e.getMessage());
logger.debug("Exception caught when attempting to read the configuration.", e);
return true; return true;
} }
} }

View File

@@ -176,8 +176,12 @@ public class ModeledUserContext extends RestrictedObject
* invocation has any effect. If this function is never invoked, no * invocation has any effect. If this function is never invoked, no
* activity record will be recorded, including when this UserContext is * activity record will be recorded, including when this UserContext is
* invalidated. * invalidated.
*
* @throws GuacamoleException
* If an error occurs retrieving configuration information from the
* environment.
*/ */
public void recordUserLogin() { public void recordUserLogin() throws GuacamoleException {
// Do nothing if invoked multiple times // Do nothing if invoked multiple times
if (userRecord != null) if (userRecord != null)
@@ -190,7 +194,7 @@ public class ModeledUserContext extends RestrictedObject
userRecord.setRemoteHost(getCurrentUser().getCredentials().getRemoteAddress()); userRecord.setRemoteHost(getCurrentUser().getCredentials().getRemoteAddress());
// Insert record representing login // Insert record representing login
userRecordMapper.insert(userRecord); userRecordMapper.insert(userRecord, environment.getCaseSensitiveUsernames());
} }

View File

@@ -39,13 +39,18 @@ public interface PasswordRecordMapper extends ModeledDirectoryObjectMapper<UserM
* @param maxHistorySize * @param maxHistorySize
* The maximum number of records to maintain for each user. * The maximum number of records to maintain for each user.
* *
* @param caseSensitive
* true if the username being queried should be evaluated in a
* case-sensitive manner, otherwise false.
*
* @return * @return
* A collection of all password records associated with the user having * A collection of all password records associated with the user having
* the given username. This collection will be empty if no such user * the given username. This collection will be empty if no such user
* exists. * exists.
*/ */
List<PasswordRecordModel> select(@Param("username") String username, List<PasswordRecordModel> select(@Param("username") String username,
@Param("maxHistorySize") int maxHistorySize); @Param("maxHistorySize") int maxHistorySize,
@Param("caseSensitive") boolean caseSensitive);
/** /**
* Inserts the given password record. Old records exceeding the maximum * Inserts the given password record. Old records exceeding the maximum

View File

@@ -19,6 +19,7 @@
package org.apache.guacamole.auth.jdbc.user; package org.apache.guacamole.auth.jdbc.user;
import java.util.Collection;
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper; import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
@@ -34,9 +35,81 @@ public interface UserMapper extends ModeledDirectoryObjectMapper<UserModel> {
* @param username * @param username
* The username of the user to return. * The username of the user to return.
* *
* @param caseSensitive
* true if the search should evaluate usernames in a case-sensitive
* manner, otherwise false.
*
* @return * @return
* The user having the given username, or null if no such user exists. * The user having the given username, or null if no such user exists.
*/ */
UserModel selectOne(@Param("username") String username); UserModel selectOne(@Param("username") String username,
@Param("caseSensitive") boolean caseSensitive);
/**
* Selects all users which have the given identifiers. If an identifier
* has no corresponding object, it will be ignored. This should only be
* called on behalf of a system administrator. If users are needed by a
* non-administrative user who must have explicit read rights, use
* selectReadable() instead.
*
* @param identifiers
* The identifiers of the users to return.
*
* @param caseSensitive
* true if the query should evaluate username identifiers in a
* case-sensitive manner, otherwise false.
*
* @return
* A Collection of all objects having the given identifiers.
*/
Collection<UserModel> select(@Param("identifiers") Collection<String> identifiers,
@Param("caseSensitive") boolean caseSensitive);
/**
* Selects all users which have the given identifiers and are explicitly
* readable by the given user. If an identifier has no corresponding
* object, or the corresponding user is unreadable, it will be ignored.
* If users are needed by a system administrator (who, by definition,
* does not need explicit read rights), use select() instead.
*
* @param user
* The user whose permissions should determine whether an object
* is returned.
*
* @param identifiers
* The identifiers of the users to return.
*
* @param effectiveGroups
* The identifiers of any known effective groups that should be taken
* into account, such as those defined externally to the database.
*
* @param caseSensitive
* true if the query should evaluate username identifiers in a
* case-sensitive manner, otherwise false.
*
* @return
* A Collection of all objects having the given identifiers.
*/
Collection<UserModel> selectReadable(@Param("user") UserModel user,
@Param("identifiers") Collection<String> identifiers,
@Param("effectiveGroups") Collection<String> effectiveGroups,
@Param("caseSensitive") boolean caseSensitive);
/**
* Deletes the given user from the database. If the user does not
* exist, this operation has no effect.
*
* @param identifier
* The identifier of the user to delete.
*
* @param caseSensitive
* true if the query should evaluate username identifiers in a
* case-sensitive manner, otherwise false.
*
* @return
* The number of rows deleted.
*/
int delete(@Param("identifier") String identifier,
@Param("caseSensitive") boolean caseSensitive);
} }

View File

@@ -33,6 +33,7 @@ import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectService;
import org.apache.guacamole.GuacamoleClientException; import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleUnsupportedException; import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
import org.apache.guacamole.auth.jdbc.base.ActivityRecordModel; import org.apache.guacamole.auth.jdbc.base.ActivityRecordModel;
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm; import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate; import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
@@ -156,6 +157,12 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
@Inject @Inject
private PasswordPolicyService passwordPolicyService; private PasswordPolicyService passwordPolicyService;
/**
* The server environment for retrieving configuration.
*/
@Inject
private JDBCEnvironment environment;
@Override @Override
protected ModeledDirectoryObjectMapper<UserModel> getObjectMapper() { protected ModeledDirectoryObjectMapper<UserModel> getObjectMapper() {
return userMapper; return userMapper;
@@ -241,7 +248,8 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
throw new GuacamoleClientException("The username must not be blank."); throw new GuacamoleClientException("The username must not be blank.");
// Do not create duplicate users // Do not create duplicate users
Collection<UserModel> existing = userMapper.select(Collections.singleton(model.getIdentifier())); Collection<UserModel> existing = userMapper.select(Collections.singleton(
model.getIdentifier()), environment.getCaseSensitiveUsernames());
if (!existing.isEmpty()) if (!existing.isEmpty())
throw new GuacamoleClientException("User \"" + model.getIdentifier() + "\" already exists."); throw new GuacamoleClientException("User \"" + model.getIdentifier() + "\" already exists.");
@@ -277,7 +285,8 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
throw new GuacamoleClientException("The username must not be blank."); throw new GuacamoleClientException("The username must not be blank.");
// Check whether such a user is already present // Check whether such a user is already present
UserModel existing = userMapper.selectOne(model.getIdentifier()); UserModel existing = userMapper.selectOne(model.getIdentifier(),
environment.getCaseSensitiveUsernames());
if (existing != null) { if (existing != null) {
// Do not rename to existing user // Do not rename to existing user
@@ -338,6 +347,17 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
} }
@Override
public void deleteObject(ModeledAuthenticatedUser user, String identifier)
throws GuacamoleException {
beforeDelete(user, identifier);
// Delete object
userMapper.delete(identifier, environment.getCaseSensitiveUsernames());
}
@Override @Override
protected boolean isValidIdentifier(String identifier) { protected boolean isValidIdentifier(String identifier) {
@@ -375,7 +395,8 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
String password = credentials.getPassword(); String password = credentials.getPassword();
// Retrieve corresponding user model, if such a user exists // Retrieve corresponding user model, if such a user exists
UserModel userModel = userMapper.selectOne(username); UserModel userModel = userMapper.selectOne(username,
environment.getCaseSensitiveUsernames());
if (userModel == null) if (userModel == null)
return null; return null;
@@ -416,7 +437,8 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
AuthenticatedUser authenticatedUser) throws GuacamoleException { AuthenticatedUser authenticatedUser) throws GuacamoleException {
// Retrieve corresponding user model, if such a user exists // Retrieve corresponding user model, if such a user exists
UserModel userModel = userMapper.selectOne(authenticatedUser.getIdentifier()); UserModel userModel = userMapper.selectOne(authenticatedUser.getIdentifier(),
environment.getCaseSensitiveUsernames());
if (userModel == null) if (userModel == null)
return null; return null;
@@ -614,14 +636,16 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
// Bypass permission checks if the user is privileged or has System-level audit permissions // Bypass permission checks if the user is privileged or has System-level audit permissions
if (user.isPrivileged() || user.getUser().getEffectivePermissions().getSystemPermissions().hasPermission(SystemPermission.Type.AUDIT)) if (user.isPrivileged() || user.getUser().getEffectivePermissions().getSystemPermissions().hasPermission(SystemPermission.Type.AUDIT))
searchResults = userRecordMapper.search(username, recordIdentifier, searchResults = userRecordMapper.search(username, recordIdentifier,
requiredContents, sortPredicates, limit); requiredContents, sortPredicates, limit,
environment.getCaseSensitiveUsernames());
// Otherwise only return explicitly readable history records // Otherwise only return explicitly readable history records
else else
searchResults = userRecordMapper.searchReadable(username, searchResults = userRecordMapper.searchReadable(username,
user.getUser().getModel(), recordIdentifier, user.getUser().getModel(), recordIdentifier,
requiredContents, sortPredicates, limit, requiredContents, sortPredicates, limit,
user.getEffectiveUserGroups()); user.getEffectiveUserGroups(),
environment.getCaseSensitiveUsernames());
return getObjectInstances(searchResults); return getObjectInstances(searchResults);

View File

@@ -19,10 +19,67 @@
package org.apache.guacamole.auth.jdbc.usergroup; package org.apache.guacamole.auth.jdbc.usergroup;
import java.util.Collection;
import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper; import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper;
import org.apache.ibatis.annotations.Param;
/** /**
* Mapper for the one-to-many relationship between a user group and its user * Mapper for the one-to-many relationship between a user group and its user
* members. * members.
*/ */
public interface UserGroupMemberUserMapper extends ObjectRelationMapper<UserGroupModel> {} public interface UserGroupMemberUserMapper extends ObjectRelationMapper<UserGroupModel> {
/**
* Inserts rows as necessary to establish the one-to-many relationship
* represented by the RelatedObjectSet between the given parent and
* children. If the relation for any parent/child pair is already present,
* no attempt is made to insert a new row for that relation.
*
* @param parent
* The model of the object on the parent side of the one-to-many
* relationship represented by the RelatedObjectSet.
*
* @param children
* The identifiers of the objects on the child side of the one-to-many
* relationship represented by the RelatedObjectSet.
*
* @param caseSensitive
* True if username case should be respected when looking up the username
* in the guacamole_entity table, or false if the query to the
* guacamole_entity table should be done case-insensitively.
*
* @return
* The number of rows inserted.
*/
int insert(@Param("parent") UserGroupModel parent,
@Param("children") Collection<String> children,
@Param("caseSensitive") boolean caseSensitive);
/**
* Deletes rows as necessary to modify the one-to-many relationship
* represented by the RelatedObjectSet between the given parent and
* children. If the relation for any parent/child pair does not exist,
* that specific relation is ignored, and deletion proceeds with the
* remaining relations.
*
* @param parent
* The model of the object on the parent side of the one-to-many
* relationship represented by the RelatedObjectSet.
*
* @param children
* The identifiers of the objects on the child side of the one-to-many
* relationship represented by the RelatedObjectSet.
*
* @param caseSensitive
* True if username case should be respected when looking up the username
* in the guacamole_entity table, or false if the query to the
* guacamole_entity table should be done case-insensitively.
*
* @return
* The number of rows deleted.
*/
int delete(@Param("parent") UserGroupModel parent,
@Param("children") Collection<String> children,
@Param("caseSesitive") boolean caseSensitive);
}

View File

@@ -446,11 +446,23 @@ public class MySQLEnvironment extends JDBCEnvironment {
@Override @Override
public boolean getCaseSensitiveUsernames() throws GuacamoleException { public boolean getCaseSensitiveUsernames() throws GuacamoleException {
return getProperty( // Get the configured value for the property.
boolean caseSensitiveUsernames = getProperty(
MySQLGuacamoleProperties.MYSQL_CASE_SENSITIVE_USERNAMES, MySQLGuacamoleProperties.MYSQL_CASE_SENSITIVE_USERNAMES,
false super.getCaseSensitiveUsernames()
); );
// If property has been set to true, warn the admin.
if (caseSensitiveUsernames)
logger.warn("You have enabled case-sensitive usernames; however, "
+ "MySQL's default collations do not support case-sensitive "
+ "string comparisons. If you really want case-sensitive "
+ "usernames you will need to configure your database "
+ "appropriately.");
// Return the configured setting.
return caseSensitiveUsernames;
} }
} }

View File

@@ -303,6 +303,12 @@ public class MySQLGuacamoleProperties {
}; };
/**
* A property used to configure whether or not usernames within the MySQL
* JDBC module should be treated as case-sensitive. Be aware that MySQL's
* default database collations do not do case-sensitive comparisons, so in
* many cases they will effectively be case-insensitive.
*/
public static final BooleanGuacamoleProperty MYSQL_CASE_SENSITIVE_USERNAMES = public static final BooleanGuacamoleProperty MYSQL_CASE_SENSITIVE_USERNAMES =
new BooleanGuacamoleProperty() { new BooleanGuacamoleProperty() {

View File

@@ -61,7 +61,14 @@
(SELECT user_id FROM guacamole_user (SELECT user_id FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
guacamole_entity.name = #{record.username,jdbcType=VARCHAR} guacamole_entity.name = #{record.username,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(guacamole_entity.name) = LOWER(#{record.username,jdbcType=VARCHAR})
</otherwise>
</choose>
AND guacamole_entity.type = 'USER'), AND guacamole_entity.type = 'USER'),
#{record.username,jdbcType=VARCHAR}, #{record.username,jdbcType=VARCHAR},
#{record.startDate,jdbcType=TIMESTAMP}, #{record.startDate,jdbcType=TIMESTAMP},
@@ -112,7 +119,15 @@
guacamole_connection_history.user_id IN ( guacamole_connection_history.user_id IN (
SELECT user_id SELECT user_id
FROM guacamole_user FROM guacamole_user
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0 WHERE
<choose>
<when test="caseSensitive">
POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
</when>
<otherwise>
POSITION(LOWER(#{term.term,jdbcType=VARCHAR}) IN LOWER(username)) > 0
</otherwise>
</choose>
) )
OR guacamole_connection_history.connection_id IN ( OR guacamole_connection_history.connection_id IN (
@@ -200,7 +215,14 @@
FROM guacamole_user FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0 POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
</when>
<otherwise>
POSITION(LOWER(#{term.term,jdbcType=VARCHAR}) IN LOWER(guacamole_entity.name)) > 0
</otherwise>
</choose>
AND guacamole_entity.type = 'USER' AND guacamole_entity.type = 'USER'
) )

View File

@@ -68,7 +68,15 @@
<property name="groups" value="effectiveGroups"/> <property name="groups" value="effectiveGroups"/>
</include> </include>
AND permission = #{type,jdbcType=VARCHAR} AND permission = #{type,jdbcType=VARCHAR}
AND affected_entity.name = #{identifier,jdbcType=VARCHAR} AND
<choose>
<when test="caseSensitive">
affected_entity.name = #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(affected_entity.name) = LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
AND affected_entity.type = 'USER' AND affected_entity.type = 'USER'
</select> </select>
@@ -86,11 +94,23 @@
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/> <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/> <property name="groups" value="effectiveGroups"/>
</include> </include>
AND affected_entity.name IN AND
<choose>
<when test="caseSensitive">
affected_entity.name IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</foreach> </foreach>
</when>
<otherwise>
LOWER(affected_entity.name) IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
LOWER(#{identifier,jdbcType=VARCHAR})
</foreach>
</otherwise>
</choose>
AND permission IN AND permission IN
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="," close=")"> open="(" separator="," close=")">
@@ -108,6 +128,8 @@
JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
(guacamole_user_permission.entity_id, permission, affected_entity.name) IN (guacamole_user_permission.entity_id, permission, affected_entity.name) IN
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="," close=")"> open="(" separator="," close=")">
@@ -115,6 +137,17 @@
#{permission.type,jdbcType=VARCHAR}, #{permission.type,jdbcType=VARCHAR},
#{permission.objectIdentifier,jdbcType=VARCHAR}) #{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach> </foreach>
</when>
<otherwise>
AND (guacamole_user_permission.entity_id, permission, LOWER(affected_entity.name)) IN
<foreach collection="permissions" item="permission"
open="(" separator="," close=")">
(#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR},
LOWER(#{permission.objectIdentifier,jdbcType=VARCHAR}))
</foreach>
</otherwise>
</choose>
AND affected_entity.type = 'USER' AND affected_entity.type = 'USER'
</delete> </delete>
@@ -140,7 +173,14 @@
</foreach> </foreach>
AS permissions AS permissions
JOIN guacamole_entity affected_entity ON JOIN guacamole_entity affected_entity ON
<choose>
<when test="caseSensitive">
affected_entity.name = permissions.affected_name affected_entity.name = permissions.affected_name
</when>
<otherwise>
LOWER(affected_entity.name) = LOWER(permissions.affected_name)
</otherwise>
</choose>
AND affected_entity.type = 'USER' AND affected_entity.type = 'USER'
JOIN guacamole_user affected_user ON affected_user.entity_id = affected_entity.entity_id JOIN guacamole_user affected_user ON affected_user.entity_id = affected_entity.entity_id

View File

@@ -43,7 +43,14 @@
JOIN guacamole_user ON guacamole_user_password_history.user_id = guacamole_user.user_id JOIN guacamole_user ON guacamole_user_password_history.user_id = guacamole_user.user_id
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
guacamole_entity.name = #{username,jdbcType=VARCHAR} guacamole_entity.name = #{username,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(guacamole_entity.name) = LOWER(#{username,jdbcType=VARCHAR})
</otherwise>
</choose>
ORDER BY ORDER BY
guacamole_user_password_history.password_date DESC guacamole_user_password_history.password_date DESC
LIMIT #{maxHistorySize} LIMIT #{maxHistorySize}

View File

@@ -130,10 +130,26 @@
FROM guacamole_user FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
WHERE guacamole_entity.name IN WHERE
<choose>
<when test="caseSensitive">
guacamole_entity.name
</when>
<otherwise>
LOWER(guacamole_entity.name)
</otherwise>
</choose>
IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
<choose>
<when test="caseSensitive">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</foreach> </foreach>
AND guacamole_entity.type = 'USER' AND guacamole_entity.type = 'USER'
GROUP BY guacamole_user.user_id, guacamole_entity.entity_id; GROUP BY guacamole_user.user_id, guacamole_entity.entity_id;
@@ -145,10 +161,26 @@
FROM guacamole_user_attribute FROM guacamole_user_attribute
JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE guacamole_entity.name IN WHERE
<choose>
<when test="caseSensitive">
guacamole_entity.name
</when>
<otherwise>
LOWER(guacamole_entity.name)
</otherwise>
</choose>
IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
<choose>
<when test="caseSensitive">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</foreach> </foreach>
AND guacamole_entity.type = 'USER'; AND guacamole_entity.type = 'USER';
@@ -180,10 +212,26 @@
FROM guacamole_user FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
WHERE guacamole_entity.name IN WHERE
<choose>
<when test="caseSensitive">
guacamole_entity.name
</when>
<otherwise>
LOWER(guacamole_entity.name)
</otherwise>
</choose>
IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
<choose>
<when test="caseSensitive">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</foreach> </foreach>
AND guacamole_entity.type = 'USER' AND guacamole_entity.type = 'USER'
AND guacamole_user.user_id IN ( AND guacamole_user.user_id IN (
@@ -201,10 +249,26 @@
FROM guacamole_user_attribute FROM guacamole_user_attribute
JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE guacamole_entity.name IN WHERE
<choose>
<when test="caseSensitive">
guacamole_entity.name
</when>
<otherwise>
LOWER(guacamole_entity.name)
</otherwise>
</choose>
IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
<choose>
<when test="caseSensitive">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</foreach> </foreach>
AND guacamole_entity.type = 'USER' AND guacamole_entity.type = 'USER'
AND guacamole_user.user_id IN ( AND guacamole_user.user_id IN (
@@ -243,7 +307,14 @@
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
WHERE WHERE
<choose>
<when test="caseSensitive">
guacamole_entity.name = #{username,jdbcType=VARCHAR} guacamole_entity.name = #{username,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(guacamole_entity.name) = LOWER(#{username,jdbcType=VARCHAR})
</otherwise>
</choose>
AND guacamole_entity.type = 'USER' AND guacamole_entity.type = 'USER'
GROUP BY guacamole_user.user_id, guacamole_entity.entity_id; GROUP BY guacamole_user.user_id, guacamole_entity.entity_id;
@@ -255,7 +326,14 @@
JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
guacamole_entity.name = #{username,jdbcType=VARCHAR} guacamole_entity.name = #{username,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(guacamole_entity.name) = LOWER(#{username,jdbcType=VARCHAR})
</otherwise>
</choose>
AND guacamole_entity.type = 'USER' AND guacamole_entity.type = 'USER'
</select> </select>
@@ -264,7 +342,14 @@
<delete id="delete"> <delete id="delete">
DELETE FROM guacamole_entity DELETE FROM guacamole_entity
WHERE WHERE
<choose>
<when test="caseSensitive">
name = #{identifier,jdbcType=VARCHAR} name = #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(name) = LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
AND type = 'USER' AND type = 'USER'
</delete> </delete>

View File

@@ -49,7 +49,14 @@
(SELECT user_id FROM guacamole_user (SELECT user_id FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
guacamole_entity.name = #{record.username,jdbcType=VARCHAR} guacamole_entity.name = #{record.username,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(guacamole_entity.name) = LOWER(#{record.username,jdbcType=VARCHAR})
</otherwise>
</choose>
AND guacamole_entity.type = 'USER'), AND guacamole_entity.type = 'USER'),
#{record.username,jdbcType=VARCHAR}, #{record.username,jdbcType=VARCHAR},
#{record.startDate,jdbcType=TIMESTAMP}, #{record.startDate,jdbcType=TIMESTAMP},
@@ -81,7 +88,14 @@
<where> <where>
<if test="identifier != null"> <if test="identifier != null">
<choose>
<when test="caseSensitive">
guacamole_user_history.username = #{identifier,jdbcType=VARCHAR} guacamole_user_history.username = #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(guacamole_user_history.username) = LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</if> </if>
<foreach collection="terms" item="term" open=" AND " separator=" AND "> <foreach collection="terms" item="term" open=" AND " separator=" AND ">
@@ -92,7 +106,14 @@
FROM guacamole_user FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0 POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
</when>
<otherwise>
POSITION(LOWER(#{term.term,jdbcType=VARCHAR}) IN LOWER(guacamole_entity.name)) > 0
</otherwise>
</choose>
AND guacamole_entity.type = 'USER'), AND guacamole_entity.type = 'USER'),
) )
@@ -146,7 +167,15 @@
) )
<if test="identifier != null"> <if test="identifier != null">
AND guacamole_entity.name = #{identifier,jdbcType=VARCHAR} AND
<choose>
<when test="caseSensitive">
guacamole_entity.name = #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(guacamole_entity.name) = LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</if> </if>
<foreach collection="terms" item="term" open=" AND " separator=" AND "> <foreach collection="terms" item="term" open=" AND " separator=" AND ">
@@ -157,7 +186,14 @@
FROM guacamole_user FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0 POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
</when>
<otherwise>
POSITION(LOWER(#{term.term,jdbcType=VARCHAR}) IN LOWER(guacamole_entity.name)) > 0
</otherwise>
</choose>
AND guacamole_entity.type = 'USER' AND guacamole_entity.type = 'USER'
) )

View File

@@ -58,10 +58,26 @@
WHERE WHERE
user_group_id = #{parent.objectID,jdbcType=INTEGER} user_group_id = #{parent.objectID,jdbcType=INTEGER}
AND guacamole_entity.type = 'USER' AND guacamole_entity.type = 'USER'
AND guacamole_entity.name IN AND
<choose>
<when test="caseSensitive">
guacamole_entity.name
</when>
<otherwise>
LOWER(guacamole_entity.name)
</otherwise>
</choose>
IN
<foreach collection="children" item="identifier" <foreach collection="children" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
<choose>
<when test="caseSensitive">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</foreach> </foreach>
</delete> </delete>
@@ -76,10 +92,25 @@
guacamole_entity.entity_id guacamole_entity.entity_id
FROM guacamole_entity FROM guacamole_entity
WHERE WHERE
guacamole_entity.name IN <choose>
<when test="caseSensitive">
guacamole_entity.name
</when>
<otherwise>
LOWER(guacamole_entity.name)
</otherwise>
</choose>
IN
<foreach collection="children" item="identifier" <foreach collection="children" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
<choose>
<when test="caseSensitive">
#{identifier} #{identifier}
</when>
<otherwise>
LOWER(#{identifier})
</otherwise>
</choose>
</foreach> </foreach>
AND guacamole_entity.type = 'USER' AND guacamole_entity.type = 'USER'
AND guacamole_entity.entity_id NOT IN ( AND guacamole_entity.entity_id NOT IN (

View File

@@ -402,11 +402,14 @@ public class PostgreSQLEnvironment extends JDBCEnvironment {
@Override @Override
public boolean getCaseSensitiveUsernames() throws GuacamoleException { public boolean getCaseSensitiveUsernames() throws GuacamoleException {
// By default, PostgreSQL does use case-sensitive string searches, so // By default, PostgreSQL does perform case-sensitive string comparisons.
// we will honor case-sensitive usernames. // Even though usernames are generally not case-sensitive across
// most authenticaiton systems, we've elected to maintain case-
// sensitivity in this module in order to avoid surprising anyone who
// may be relying upon it.
return getProperty( return getProperty(
PostgreSQLGuacamoleProperties.POSTGRESQL_CASE_SENSITIVE_USERNAMES, PostgreSQLGuacamoleProperties.POSTGRESQL_CASE_SENSITIVE_USERNAMES,
true super.getCaseSensitiveUsernames()
); );
} }

View File

@@ -316,8 +316,8 @@ public class PostgreSQLGuacamoleProperties {
}; };
/** /**
* A property that configures whether or not usernames should be treated as * A property used to configure whether or not usernames within the Postgres
* case-sensitive with the Postgres JDBC backend. * JDBC module should be treated as case-sensitive.
*/ */
public static final BooleanGuacamoleProperty POSTGRESQL_CASE_SENSITIVE_USERNAMES = public static final BooleanGuacamoleProperty POSTGRESQL_CASE_SENSITIVE_USERNAMES =
new BooleanGuacamoleProperty() { new BooleanGuacamoleProperty() {

View File

@@ -61,7 +61,14 @@
(SELECT user_id FROM guacamole_user (SELECT user_id FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
guacamole_entity.name = #{record.username,jdbcType=VARCHAR} guacamole_entity.name = #{record.username,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(guacamole_entity.name) = LOWER(#{record.username,jdbcType=VARCHAR})
</otherwise>
</choose>
AND guacamole_entity.type = 'USER'::guacamole_entity_type), AND guacamole_entity.type = 'USER'::guacamole_entity_type),
#{record.username,jdbcType=VARCHAR}, #{record.username,jdbcType=VARCHAR},
#{record.startDate,jdbcType=TIMESTAMP}, #{record.startDate,jdbcType=TIMESTAMP},
@@ -110,7 +117,15 @@
guacamole_connection_history.user_id IN ( guacamole_connection_history.user_id IN (
SELECT user_id SELECT user_id
FROM guacamole_user FROM guacamole_user
WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0 WHERE
<choose>
<when test="caseSensitive">
POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
</when>
<otherwise>
POSITION(LOWER(#{term.term,jdbcType=VARCHAR}) IN LOWER(username)) > 0
</otherwise>
</choose>
) )
OR guacamole_connection_history.connection_id IN ( OR guacamole_connection_history.connection_id IN (
@@ -198,7 +213,14 @@
FROM guacamole_user FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0 POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
</when>
<otherwise>
POSITION(LOWER(#{term.term,jdbcType=VARCHAR}) IN LOWER(guacamole_entity.name)) > 0
</otherwise>
</choose>
AND guacamole_entity.type = 'USER'::guacamole_entity_type AND guacamole_entity.type = 'USER'::guacamole_entity_type
) )

View File

@@ -28,7 +28,7 @@
<result column="entity_id" property="entityID" jdbcType="INTEGER"/> <result column="entity_id" property="entityID" jdbcType="INTEGER"/>
<result column="permission" property="type" jdbcType="VARCHAR" <result column="permission" property="type" jdbcType="VARCHAR"
javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/> javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
<result column="affected_name" property="objectIdentifier" jdbcType="INTEGER"/> <result column="affected_name" property="objectIdentifier" jdbcType="VARCHAR"/>
</resultMap> </resultMap>
<!-- Select all permissions for a given entity --> <!-- Select all permissions for a given entity -->
@@ -68,7 +68,16 @@
<property name="groups" value="effectiveGroups"/> <property name="groups" value="effectiveGroups"/>
</include> </include>
AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
AND affected_entity.name = #{identifier,jdbcType=VARCHAR} AND
<choose>
<when test="caseSensitive">
affected_entity.name = #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(affected_entity.name) = LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
AND affected_entity.type = 'USER'::guacamole_entity_type AND affected_entity.type = 'USER'::guacamole_entity_type
</select> </select>
@@ -86,11 +95,23 @@
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/> <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/> <property name="groups" value="effectiveGroups"/>
</include> </include>
AND affected_entity.name IN AND
<choose>
<when test="caseSensitive">
affected_entity.name IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</foreach> </foreach>
</when>
<otherwise>
LOWER(affected_entity.name) IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
LOWER(#{identifier,jdbcType=VARCHAR})
</foreach>
</otherwise>
</choose>
AND permission IN AND permission IN
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="," close=")"> open="(" separator="," close=")">
@@ -108,13 +129,26 @@
WHERE WHERE
guacamole_user_permission.affected_user_id = affected_user.user_id guacamole_user_permission.affected_user_id = affected_user.user_id
AND affected_user.entity_id = affected_entity.entity_id AND affected_user.entity_id = affected_entity.entity_id
<choose>
<when test="caseSensitive">
AND (guacamole_user_permission.entity_id, permission, affected_entity.name) IN AND (guacamole_user_permission.entity_id, permission, affected_entity.name) IN
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="," close=")"> open="(" separator="," close=")">
(#{permission.entityID,jdbcType=INTEGER}, (#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type,
#{permission.objectIdentifier,jdbcType=INTEGER}) #{permission.objectIdentifier,jdbcType=VARCHAR})
</foreach> </foreach>
</when>
<otherwise>
AND (guacamole_user_permission.entity_id, permission, LOWER(affected_entity.name)) IN
<foreach collection="permissions" item="permission"
open="(" separator="," close=")">
(#{permission.entityID,jdbcType=INTEGER},
#{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type,
LOWER(#{permission.objectIdentifier,jdbcType=VARCHAR}))
</foreach>
</otherwise>
</choose>
AND affected_entity.type = 'USER'::guacamole_entity_type AND affected_entity.type = 'USER'::guacamole_entity_type
</delete> </delete>
@@ -140,7 +174,14 @@
</foreach> </foreach>
AS permissions AS permissions
JOIN guacamole_entity affected_entity ON JOIN guacamole_entity affected_entity ON
<choose>
<when test="caseSensitive">
affected_entity.name = permissions.affected_name affected_entity.name = permissions.affected_name
</when>
<otherwise>
LOWER(affected_entity.name) = LOWER(permissions.affected_name)
</otherwise>
</choose>
AND affected_entity.type = 'USER'::guacamole_entity_type AND affected_entity.type = 'USER'::guacamole_entity_type
JOIN guacamole_user affected_user ON affected_user.entity_id = affected_entity.entity_id JOIN guacamole_user affected_user ON affected_user.entity_id = affected_entity.entity_id
WHERE (permissions.entity_id, permissions.permission, affected_user.user_id) NOT IN ( WHERE (permissions.entity_id, permissions.permission, affected_user.user_id) NOT IN (

View File

@@ -43,7 +43,14 @@
JOIN guacamole_user ON guacamole_user_password_history.user_id = guacamole_user.user_id JOIN guacamole_user ON guacamole_user_password_history.user_id = guacamole_user.user_id
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
guacamole_entity.name = #{username,jdbcType=VARCHAR} guacamole_entity.name = #{username,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(guacamole_entity.name) = LOWER(#{username,jdbcType=VARCHAR})
</otherwise>
</choose>
ORDER BY ORDER BY
guacamole_user_password_history.password_date DESC guacamole_user_password_history.password_date DESC
LIMIT #{maxHistorySize} LIMIT #{maxHistorySize}

View File

@@ -130,10 +130,26 @@
FROM guacamole_user FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
WHERE guacamole_entity.name IN WHERE
<choose>
<when test="caseSensitive">
guacamole_entity.name
</when>
<otherwise>
LOWER(guacamole_entity.name)
</otherwise>
</choose>
IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
<choose>
<when test="caseSensitive">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</foreach> </foreach>
AND guacamole_entity.type = 'USER'::guacamole_entity_type AND guacamole_entity.type = 'USER'::guacamole_entity_type
GROUP BY guacamole_user.user_id, guacamole_entity.entity_id; GROUP BY guacamole_user.user_id, guacamole_entity.entity_id;
@@ -145,10 +161,26 @@
FROM guacamole_user_attribute FROM guacamole_user_attribute
JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE guacamole_entity.name IN WHERE
<choose>
<when test="caseSensitive">
guacamole_entity.name
</when>
<otherwise>
LOWER(guacamole_entity.name)
</otherwise>
</choose>
IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
<choose>
<when test="caseSensitive">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</foreach> </foreach>
AND guacamole_entity.type = 'USER'::guacamole_entity_type; AND guacamole_entity.type = 'USER'::guacamole_entity_type;
@@ -180,10 +212,26 @@
FROM guacamole_user FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
WHERE guacamole_entity.name IN WHERE
<choose>
<when test="caseSensitive">
guacamole_entity.name
</when>
<otherwise>
LOWER(guacamole_entity.name)
</otherwise>
</choose>
IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
<choose>
<when test="caseSensitive">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</foreach> </foreach>
AND guacamole_entity.type = 'USER'::guacamole_entity_type AND guacamole_entity.type = 'USER'::guacamole_entity_type
AND guacamole_user.user_id IN ( AND guacamole_user.user_id IN (
@@ -201,10 +249,26 @@
FROM guacamole_user_attribute FROM guacamole_user_attribute
JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE guacamole_entity.name IN WHERE
<choose>
<when test="caseSensitive">
guacamole_entity.name
</when>
<otherwise>
LOWER(guacamole_entity.name)
</otherwise>
</choose>
IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
<choose>
<when test="caseSensitive">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</foreach> </foreach>
AND guacamole_entity.type = 'USER'::guacamole_entity_type AND guacamole_entity.type = 'USER'::guacamole_entity_type
AND guacamole_user.user_id IN ( AND guacamole_user.user_id IN (
@@ -243,7 +307,14 @@
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
WHERE WHERE
<choose>
<when test="caseSensitive">
guacamole_entity.name = #{username,jdbcType=VARCHAR} guacamole_entity.name = #{username,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(guacamole_entity.name) = LOWER(#{username,jdbcType=VARCHAR})
</otherwise>
</choose>
AND guacamole_entity.type = 'USER'::guacamole_entity_type AND guacamole_entity.type = 'USER'::guacamole_entity_type
GROUP BY guacamole_user.user_id, guacamole_entity.entity_id; GROUP BY guacamole_user.user_id, guacamole_entity.entity_id;
@@ -255,16 +326,29 @@
JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
guacamole_entity.name = #{username,jdbcType=VARCHAR} guacamole_entity.name = #{username,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(guacamole_entity.name) = LOWER(#{username,jdbcType=VARCHAR})
</otherwise>
</choose>
AND guacamole_entity.type = 'USER'::guacamole_entity_type AND guacamole_entity.type = 'USER'::guacamole_entity_type
</select> </select>
<!-- Delete single user by username --> <!-- Delete single user by username -->
<delete id="delete"> <delete id="delete">
DELETE FROM guacamole_entity DELETE FROM guacamole_entity
WHERE WHERE
<choose>
<when test="caseSensitive">
name = #{identifier,jdbcType=VARCHAR} name = #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(name) = LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
AND type = 'USER'::guacamole_entity_type AND type = 'USER'::guacamole_entity_type
</delete> </delete>
@@ -326,7 +410,7 @@
email_address = #{object.emailAddress,jdbcType=VARCHAR}, email_address = #{object.emailAddress,jdbcType=VARCHAR},
organization = #{object.organization,jdbcType=VARCHAR}, organization = #{object.organization,jdbcType=VARCHAR},
organizational_role = #{object.organizationalRole,jdbcType=VARCHAR} organizational_role = #{object.organizationalRole,jdbcType=VARCHAR}
WHERE user_id = #{object.objectID,jdbcType=VARCHAR} WHERE user_id = #{object.objectID,jdbcType=INTEGER}
</update> </update>
<!-- Delete attributes associated with user --> <!-- Delete attributes associated with user -->

View File

@@ -49,7 +49,14 @@
(SELECT user_id FROM guacamole_user (SELECT user_id FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
guacamole_entity.name = #{record.username,jdbcType=VARCHAR} guacamole_entity.name = #{record.username,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(guacamole_entity.name) = LOWER(#{record.username,jdbcType=VARCHAR})
</otherwise>
</choose>
AND guacamole_entity.type = 'USER'::guacamole_entity_type), AND guacamole_entity.type = 'USER'::guacamole_entity_type),
#{record.username,jdbcType=VARCHAR}, #{record.username,jdbcType=VARCHAR},
#{record.startDate,jdbcType=TIMESTAMP}, #{record.startDate,jdbcType=TIMESTAMP},
@@ -81,7 +88,14 @@
<where> <where>
<if test="identifier != null"> <if test="identifier != null">
<choose>
<when test="caseSensitive">
guacamole_user_history.username = #{identifier,jdbcType=VARCHAR} guacamole_user_history.username = #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(guacamole_user_history.username) = LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</if> </if>
<foreach collection="terms" item="term" open=" AND " separator=" AND "> <foreach collection="terms" item="term" open=" AND " separator=" AND ">
@@ -92,7 +106,14 @@
FROM guacamole_user FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0 POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
</when>
<otherwise>
POSITION(LOWER(#{term.term,jdbcType=VARCHAR}) IN LOWER(guacamole_entity.name)) > 0
</otherwise>
</choose>
AND guacamole_entity.type = 'USER'::guacamole_entity_type), AND guacamole_entity.type = 'USER'::guacamole_entity_type),
) )
@@ -146,7 +167,15 @@
) )
<if test="identifier != null"> <if test="identifier != null">
AND guacamole_entity.name = #{identifier,jdbcType=VARCHAR} AND
<choose>
<when test="caseSensitive">
guacamole_entity.name = #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(guacamole_entity.name) = LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</if> </if>
<foreach collection="terms" item="term" open=" AND " separator=" AND "> <foreach collection="terms" item="term" open=" AND " separator=" AND ">
@@ -157,7 +186,14 @@
FROM guacamole_user FROM guacamole_user
JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0 POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
</when>
<otherwise>
POSITION(LOWER(#{term.term,jdbcType=VARCHAR}) IN LOWER(guacamole_entity.name)) > 0
</otherwise>
</choose>
AND guacamole_entity.type = 'USER'::guacamole_entity_type AND guacamole_entity.type = 'USER'::guacamole_entity_type
) )

View File

@@ -58,10 +58,26 @@
user_group_id = #{parent.objectID,jdbcType=INTEGER} user_group_id = #{parent.objectID,jdbcType=INTEGER}
AND guacamole_entity.entity_id = member_entity_id AND guacamole_entity.entity_id = member_entity_id
AND guacamole_entity.type = 'USER'::guacamole_entity_type AND guacamole_entity.type = 'USER'::guacamole_entity_type
AND guacamole_entity.name IN AND
<choose>
<when test="caseSensitive">
guacamole_entity.name
</when>
<otherwise>
LOWER(guacamole_entity.name)
</otherwise>
</choose>
IN
<foreach collection="children" item="identifier" <foreach collection="children" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
<choose>
<when test="caseSensitive">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</foreach> </foreach>
</delete> </delete>
@@ -76,10 +92,25 @@
guacamole_entity.entity_id guacamole_entity.entity_id
FROM guacamole_entity FROM guacamole_entity
WHERE WHERE
guacamole_entity.name IN <choose>
<when test="caseSensitive">
guacamole_entity.name
</when>
<otherwise>
LOWER(guacamole_entity.name)
</otherwise>
</choose>
IN
<foreach collection="children" item="identifier" <foreach collection="children" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
<choose>
<when test="caseSensitive">
#{identifier} #{identifier}
</when>
<otherwise>
LOWER(#{identifier})
</otherwise>
</choose>
</foreach> </foreach>
AND guacamole_entity.type = 'USER'::guacamole_entity_type AND guacamole_entity.type = 'USER'::guacamole_entity_type
AND guacamole_entity.entity_id NOT IN ( AND guacamole_entity.entity_id NOT IN (

View File

@@ -332,13 +332,24 @@ public class SQLServerEnvironment extends JDBCEnvironment {
@Override @Override
public boolean getCaseSensitiveUsernames() throws GuacamoleException { public boolean getCaseSensitiveUsernames() throws GuacamoleException {
// SQL Server uses case-insensitive string searches by default, so // Get the configured or default value of the property.
// we do not enforce case-sensitivity unless otherwise configured. boolean caseSensitiveUsernames = getProperty(
return getProperty(
SQLServerGuacamoleProperties.SQLSERVER_CASE_SENSITIVE_USERNAMES, SQLServerGuacamoleProperties.SQLSERVER_CASE_SENSITIVE_USERNAMES,
false super.getCaseSensitiveUsernames()
); );
// If property has been set to true, warn the admin.
if (caseSensitiveUsernames)
logger.warn("You have configured this extension for case-sensitive "
+ "username comparisons, however, the default collations "
+ "for SQL Server databases do not support case-sensitive "
+ "string comparisons. Further database configuration may "
+ "be required in order for case-sensitive username "
+ "comparisons to function correctly.");
// Return as configured
return caseSensitiveUsernames;
} }
} }

View File

@@ -258,6 +258,13 @@ public class SQLServerGuacamoleProperties {
}; };
/**
* A property used to configure whether or not usernames within the SQL
* Server JDBC module should be treated as case-sensitive. While Guacamole
* will treat usernames as case-sensitive by default, SQL Server's default
* database collations do not do case-sensitive string comparisons, so in
* many cases this will effectively result in case-insensitive usernames.
*/
public static final BooleanGuacamoleProperty SQLSERVER_CASE_SENSITIVE_USERNAMES = public static final BooleanGuacamoleProperty SQLSERVER_CASE_SENSITIVE_USERNAMES =
new BooleanGuacamoleProperty() { new BooleanGuacamoleProperty() {

View File

@@ -68,7 +68,14 @@
(SELECT user_id FROM [guacamole_user] (SELECT user_id FROM [guacamole_user]
JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
[guacamole_entity].name = #{record.username,jdbcType=VARCHAR} [guacamole_entity].name = #{record.username,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER([guacamole_entity].name) = LOWER(#{record.username,jdbcType=VARCHAR})
</otherwise>
</choose>
AND [guacamole_entity].type = 'USER'), AND [guacamole_entity].type = 'USER'),
#{record.username,jdbcType=VARCHAR}, #{record.username,jdbcType=VARCHAR},
#{record.startDate,jdbcType=TIMESTAMP}, #{record.startDate,jdbcType=TIMESTAMP},
@@ -110,7 +117,15 @@
[guacamole_connection_history].user_id IN ( [guacamole_connection_history].user_id IN (
SELECT user_id SELECT user_id
FROM [guacamole_user] FROM [guacamole_user]
WHERE CHARINDEX(#{term.term,jdbcType=VARCHAR}, username) > 0 WHERE
<choose>
<when test="caseSensitive">
CHARINDEX(#{term.term,jdbcType=VARCHAR} IN username) > 0
</when>
<otherwise>
CHARINDEX(LOWER(#{term.term,jdbcType=VARCHAR}) IN LOWER(username)) > 0
</otherwise>
</choose>
) )
OR [guacamole_connection_history].connection_id IN ( OR [guacamole_connection_history].connection_id IN (
@@ -196,7 +211,14 @@
FROM [guacamole_user] FROM [guacamole_user]
JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
WHERE WHERE
CHARINDEX(#{term.term,jdbcType=VARCHAR}, [guacamole_entity].name) > 0 <choose>
<hen test="caseSensitive">
CHARINDEX(#{term.term,jdbcType=VARCHAR} IN [guacamole_entity].name) > 0
</when>
<otherwise>
CHARINDEX(LOWER(#{term.term,jdbcType=VARCHAR}) IN LOWER(guacamole_entity.name)) > 0
</otherwise>
</choose>
AND [guacamole_entity].type = 'USER' AND [guacamole_entity].type = 'USER'
) )

View File

@@ -68,7 +68,15 @@
<property name="groups" value="effectiveGroups"/> <property name="groups" value="effectiveGroups"/>
</include> </include>
AND permission = #{type,jdbcType=VARCHAR} AND permission = #{type,jdbcType=VARCHAR}
AND affected_entity.name = #{identifier,jdbcType=VARCHAR} AND
<choose>
<when test="caseSensitive">
affected_entity.name = #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(affected_entity.name) = LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
AND affected_entity.type = 'USER' AND affected_entity.type = 'USER'
</select> </select>
@@ -86,11 +94,23 @@
<property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/> <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
<property name="groups" value="effectiveGroups"/> <property name="groups" value="effectiveGroups"/>
</include> </include>
AND affected_entity.name IN AND
<choose>
<when test="caseSensitive">
affected_entity.name IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</foreach> </foreach>
</when>
<otherwise>
LOWER(affected_entity.name) IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
LOWER(#{identifier,jdbcType=VARCHAR})
</foreach>
</otherwise>
</choose>
AND permission IN AND permission IN
<foreach collection="permissions" item="permission" <foreach collection="permissions" item="permission"
open="(" separator="," close=")"> open="(" separator="," close=")">
@@ -112,7 +132,15 @@
open="(" separator=" OR " close=")"> open="(" separator=" OR " close=")">
([guacamole_user_permission].entity_id = #{permission.entityID,jdbcType=INTEGER} AND ([guacamole_user_permission].entity_id = #{permission.entityID,jdbcType=INTEGER} AND
permission = #{permission.type,jdbcType=VARCHAR} AND permission = #{permission.type,jdbcType=VARCHAR} AND
affected_entity.name = #{permission.objectIdentifier,jdbcType=VARCHAR} AND <choose>
<when test="caseSensitive">
affected_entity.name = #{permission.objectIdentifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(affected_entity.name = LOWER(#{permission.objectIdentifier,jdbcType=VARCHAR})
</otherwise>
</choose>
AND
affected_entity.type = 'USER') affected_entity.type = 'USER')
</foreach> </foreach>
@@ -139,7 +167,14 @@
</foreach> </foreach>
AS permissions AS permissions
JOIN [guacamole_entity] affected_entity ON JOIN [guacamole_entity] affected_entity ON
<choose>
<when test="caseSensitive">
affected_entity.name = permissions.affected_name affected_entity.name = permissions.affected_name
</when>
<otherwise>
LOWER(affected_entity.name) = LOWER(permissions.affected_name)
</otherwise>
</choose>
AND affected_entity.type = 'USER' AND affected_entity.type = 'USER'
JOIN [guacamole_user] affected_user ON affected_user.entity_id = affected_entity.entity_id JOIN [guacamole_user] affected_user ON affected_user.entity_id = affected_entity.entity_id
WHERE NOT EXISTS (SELECT 1 FROM [guacamole_user_permission] WHERE NOT EXISTS (SELECT 1 FROM [guacamole_user_permission]

View File

@@ -43,7 +43,14 @@
JOIN [guacamole_user] ON [guacamole_user_password_history].user_id = [guacamole_user].user_id JOIN [guacamole_user] ON [guacamole_user_password_history].user_id = [guacamole_user].user_id
JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
[guacamole_entity].name = #{username,jdbcType=VARCHAR} [guacamole_entity].name = #{username,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER([guacamole_entity].name) = LOWER(#{username,jdbcType=VARCHAR})
</otherwise>
</choose>
ORDER BY ORDER BY
[guacamole_user_password_history].password_date DESC [guacamole_user_password_history].password_date DESC

View File

@@ -133,10 +133,26 @@
) AS last_active ) AS last_active
FROM [guacamole_user] FROM [guacamole_user]
JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
WHERE [guacamole_entity].name IN WHERE
<choose>
<when test="caseSensitive">
[guacamole_entity].name
</when>
<otherwise>
LOWER([guacamole_entity].name)
</otherwise>
</choose>
IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
<choose>
<when test="caseSensitive">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</foreach> </foreach>
AND [guacamole_entity].type = 'USER'; AND [guacamole_entity].type = 'USER';
@@ -147,10 +163,26 @@
FROM [guacamole_user_attribute] FROM [guacamole_user_attribute]
JOIN [guacamole_user] ON [guacamole_user].user_id = [guacamole_user_attribute].user_id JOIN [guacamole_user] ON [guacamole_user].user_id = [guacamole_user_attribute].user_id
JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
WHERE [guacamole_entity].name IN WHERE
<choose>
<when test="caseSensitive">
[guacamole_entity].name
</when>
<otherwise>
LOWER([guacamole_entity].name)
</otherwise>
</choose>
IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
<choose>
<when test="caseSensitive">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</foreach> </foreach>
AND [guacamole_entity].type = 'USER'; AND [guacamole_entity].type = 'USER';
@@ -185,10 +217,26 @@
) AS last_active ) AS last_active
FROM [guacamole_user] FROM [guacamole_user]
JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
WHERE [guacamole_entity].name IN WHERE
<choose>
<when test="caseSensitive">
[guacamole_entity].name
</when>
<otherwise>
LOWER([guacamole_entity].name)
</otherwise>
</choose>
IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
<choose>
<when test="caseSensitive">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</foreach> </foreach>
AND [guacamole_entity].type = 'USER' AND [guacamole_entity].type = 'USER'
AND [guacamole_user].user_id IN ( AND [guacamole_user].user_id IN (
@@ -205,10 +253,26 @@
FROM [guacamole_user_attribute] FROM [guacamole_user_attribute]
JOIN [guacamole_user] ON [guacamole_user].user_id = [guacamole_user_attribute].user_id JOIN [guacamole_user] ON [guacamole_user].user_id = [guacamole_user_attribute].user_id
JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
WHERE [guacamole_entity].name IN WHERE
<choose>
<when test="caseSensitive">
[guacamole_entity].name
</when>
<otherwise>
LOWER([guacamole_entity].name)
</otherwise>
</choose>
IN
<foreach collection="identifiers" item="identifier" <foreach collection="identifiers" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
<choose>
<when test="caseSensitive">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</foreach> </foreach>
AND [guacamole_entity].type = 'USER' AND [guacamole_entity].type = 'USER'
AND [guacamole_user].user_id IN ( AND [guacamole_user].user_id IN (
@@ -250,7 +314,14 @@
FROM [guacamole_user] FROM [guacamole_user]
JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
[guacamole_entity].name = #{username,jdbcType=VARCHAR} [guacamole_entity].name = #{username,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER([guacamole_entity].name) = LOWER(#{username,jdbcType=VARCHAR})
</otherwise>
</choose>
AND [guacamole_entity].type = 'USER'; AND [guacamole_entity].type = 'USER';
SELECT SELECT
@@ -261,7 +332,14 @@
JOIN [guacamole_user] ON [guacamole_user].user_id = [guacamole_user_attribute].user_id JOIN [guacamole_user] ON [guacamole_user].user_id = [guacamole_user_attribute].user_id
JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
[guacamole_entity].name = #{username,jdbcType=VARCHAR} [guacamole_entity].name = #{username,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER([guacamole_entity].name) = LOWER(#{username,jdbcType=VARCHAR})
</otherwise>
</choose>
AND [guacamole_entity].type = 'USER' AND [guacamole_entity].type = 'USER'
</select> </select>
@@ -270,7 +348,14 @@
<delete id="delete"> <delete id="delete">
DELETE FROM [guacamole_entity] DELETE FROM [guacamole_entity]
WHERE WHERE
<choose>
<when test="caseSensitive">
name = #{identifier,jdbcType=VARCHAR} name = #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(name) = LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
AND type = 'USER' AND type = 'USER'
</delete> </delete>
@@ -332,7 +417,7 @@
email_address = #{object.emailAddress,jdbcType=VARCHAR}, email_address = #{object.emailAddress,jdbcType=VARCHAR},
organization = #{object.organization,jdbcType=VARCHAR}, organization = #{object.organization,jdbcType=VARCHAR},
organizational_role = #{object.organizationalRole,jdbcType=VARCHAR} organizational_role = #{object.organizationalRole,jdbcType=VARCHAR}
WHERE user_id = #{object.objectID,jdbcType=VARCHAR} WHERE user_id = #{object.objectID,jdbcType=INTEGER}
</update> </update>
<!-- Delete attributes associated with user --> <!-- Delete attributes associated with user -->

View File

@@ -49,7 +49,14 @@
(SELECT user_id FROM [guacamole_user] (SELECT user_id FROM [guacamole_user]
JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
WHERE WHERE
<choose>
<when test="caseSensitive">
[guacamole_entity].name = #{record.username,jdbcType=VARCHAR} [guacamole_entity].name = #{record.username,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER([guacamole_entity].name) = LOWER(#{record.username,jdbcType=VARCHAR})
</otherwise>
</choose>
AND [guacamole_entity].type = 'USER'), AND [guacamole_entity].type = 'USER'),
#{record.username,jdbcType=VARCHAR}, #{record.username,jdbcType=VARCHAR},
#{record.startDate,jdbcType=TIMESTAMP}, #{record.startDate,jdbcType=TIMESTAMP},
@@ -81,7 +88,14 @@
<where> <where>
<if test="identifier != null"> <if test="identifier != null">
<choose>
<when test="caseSensitive">
[guacamole_user_history].username = #{identifier,jdbcType=VARCHAR} [guacamole_user_history].username = #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER([guacamole_user_history].username) = LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</if> </if>
<foreach collection="terms" item="term" open=" AND " separator=" AND "> <foreach collection="terms" item="term" open=" AND " separator=" AND ">
@@ -92,7 +106,14 @@
FROM [guacamole_user] FROM [guacamole_user]
JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
WHERE WHERE
CHARINDEX(#{term.term,jdbcType=VARCHAR}, [guacamole_entity].name) > 0 <choose>
<when test="caseSensitive">
CHARINDEX(#{term.term,jdbcType=VARCHAR} IN [guacamole_entity].name) > 0
</when>
<otherwise>
CHARINDEX(LOWER(#{term.term,jdbcType=VARCHAR}) IN LOWER([guacamole_entity].name)) > 0
</otherwise>
</choose>
AND [guacamole_entity].type = 'USER'), AND [guacamole_entity].type = 'USER'),
) )
@@ -144,7 +165,15 @@
) )
<if test="identifier != null"> <if test="identifier != null">
AND [guacamole_entity].name = #{identifier,jdbcType=VARCHAR} AND
<choose>
<when test="caseSensitive">
[guacamole_entity].name = #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER([guacamole_entity].name) = LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</if> </if>
<foreach collection="terms" item="term" open=" AND " separator=" AND "> <foreach collection="terms" item="term" open=" AND " separator=" AND ">
@@ -155,7 +184,14 @@
FROM [guacamole_user] FROM [guacamole_user]
JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
WHERE WHERE
CHARINDEX(#{term.term,jdbcType=VARCHAR}, [guacamole_entity].name) > 0 <choose>
<when test="caseSensitive">
CHARINDEX(#{term.term,jdbcType=VARCHAR} IN [guacamole_entity].name) > 0
</when>
<otherwise>
CHARINDEX(LOWER(#{term.term,jdbcType=VARCHAR}) IN LOWER([guacamole_entity].name)) > 0
</otherwise>
</choose>
AND [guacamole_entity].type = 'USER' AND [guacamole_entity].type = 'USER'
) )

View File

@@ -58,10 +58,26 @@
WHERE WHERE
user_group_id = #{parent.objectID,jdbcType=INTEGER} user_group_id = #{parent.objectID,jdbcType=INTEGER}
AND [guacamole_entity].type = 'USER' AND [guacamole_entity].type = 'USER'
AND [guacamole_entity].name IN AND
<choose>
<when test="caseSensitive">
[guacamole_entity].name
</when>
<otherwise>
LOWER([guacamole_entity].name)
</otherwise>
</choose>
IN
<foreach collection="children" item="identifier" <foreach collection="children" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
<choose>
<when test="caseSensitive">
#{identifier,jdbcType=VARCHAR} #{identifier,jdbcType=VARCHAR}
</when>
<otherwise>
LOWER(#{identifier,jdbcType=VARCHAR})
</otherwise>
</choose>
</foreach> </foreach>
</delete> </delete>
@@ -76,10 +92,25 @@
[guacamole_entity].entity_id [guacamole_entity].entity_id
FROM [guacamole_entity] FROM [guacamole_entity]
WHERE WHERE
[guacamole_entity].name IN <choose>
<when test="caseSensitive">
[guacamole_entity].name
</when>
<otherwise>
LOWER([guacamole_entity].name)
</otherwise>
</choose>
IN
<foreach collection="children" item="identifier" <foreach collection="children" item="identifier"
open="(" separator="," close=")"> open="(" separator="," close=")">
<choose>
<when test="caseSensitive">
#{identifier} #{identifier}
</when>
<otherwise>
LOWER(#{identifier})
</otherwise>
</choose>
</foreach> </foreach>
AND [guacamole_entity].type = 'USER' AND [guacamole_entity].type = 'USER'
AND [guacamole_entity].entity_id NOT IN ( AND [guacamole_entity].entity_id NOT IN (

View File

@@ -1,62 +0,0 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.sso.conf;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.environment.DelegatingEnvironment;
import org.apache.guacamole.environment.LocalEnvironment;
/**
* An SSO-specific environment that defines generic properties that can be used
* with any of the implemented SSO providers.
*/
public abstract class SSOEnvironment extends DelegatingEnvironment {
/**
* Create a new instance of the SSOEnvironment using the underlying
* LocalEnvironment to read configured properties.
*/
public SSOEnvironment() {
super(LocalEnvironment.getInstance());
}
/**
* Returns true if the usernames provided to the SSO authentication
* module should be treated as case-sensitive, or false if usernames
* should be treated as case-insensitive. The default is true, usernames
* will be case-sensitive in keeping with the past behavior of Guacamole
* prior to the addition of this option.
*
* @return
* true if usernames should be treated as case-sensitive, otherwise
* false.
*
* @throws GuacamoleException
* If guacamole.properties cannot be parsed.
*/
public boolean getCaseSensitiveUsernames() throws GuacamoleException {
// While most SSO systems do not use case to differentiate between
// usernames, this currently defaults to true to avoid suddenly
// breaking any extensions that rely on case-sensitivity.
return true;
}
}