mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
GUACAMOLE-1239: Merge support for configuring username case-insensitivity.
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
|
||||
package org.apache.guacamole.auth.jdbc;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -55,6 +56,12 @@ public class HistoryTrackingConnection extends DelegatingConnection {
|
||||
* established connections.
|
||||
*/
|
||||
private final ConnectionRecordMapper connectionRecordMapper;
|
||||
|
||||
/**
|
||||
* The Guacamole server environment.
|
||||
*/
|
||||
@Inject
|
||||
private JDBCEnvironment environment;
|
||||
|
||||
/**
|
||||
* Creates a new HistoryConnection that wraps the given connection,
|
||||
@@ -98,7 +105,8 @@ public class HistoryTrackingConnection extends DelegatingConnection {
|
||||
connectionRecordModel.setConnectionName(this.getDelegateConnection().getName());
|
||||
|
||||
// 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
|
||||
ModeledConnectionRecord modeledRecord = new ModeledConnectionRecord(connectionRecordModel);
|
||||
|
@@ -38,11 +38,16 @@ public interface ActivityRecordMapper<ModelType> {
|
||||
*
|
||||
* @param record
|
||||
* The activity record to insert.
|
||||
*
|
||||
* @param caseSensitive
|
||||
* Whether or not string comparisons should be done in a case-sensitive
|
||||
* manner.
|
||||
*
|
||||
* @return
|
||||
* 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
|
||||
@@ -85,6 +90,10 @@ public interface ActivityRecordMapper<ModelType> {
|
||||
*
|
||||
* @param limit
|
||||
* 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
|
||||
* The results of the search performed with the given parameters.
|
||||
@@ -93,7 +102,8 @@ public interface ActivityRecordMapper<ModelType> {
|
||||
@Param("recordIdentifier") String recordIdentifier,
|
||||
@Param("terms") Collection<ActivityRecordSearchTerm> terms,
|
||||
@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
|
||||
@@ -132,6 +142,10 @@ public interface ActivityRecordMapper<ModelType> {
|
||||
* 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 should be done in a case-sensitive
|
||||
* manner.
|
||||
*
|
||||
* @return
|
||||
* The results of the search performed with the given parameters.
|
||||
@@ -142,6 +156,7 @@ public interface ActivityRecordMapper<ModelType> {
|
||||
@Param("terms") Collection<ActivityRecordSearchTerm> terms,
|
||||
@Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
|
||||
@Param("limit") int limit,
|
||||
@Param("effectiveGroups") Collection<String> effectiveGroups);
|
||||
@Param("effectiveGroups") Collection<String> effectiveGroups,
|
||||
@Param("caseSensitive") boolean caseSensitive);
|
||||
|
||||
}
|
||||
|
@@ -28,19 +28,20 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
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.GuacamoleException;
|
||||
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.ActivityRecordSortPredicate;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
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.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.auth.Connection;
|
||||
import org.apache.guacamole.net.auth.ConnectionRecord;
|
||||
@@ -85,6 +86,12 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
|
||||
*/
|
||||
@Inject
|
||||
private Provider<ModeledConnection> connectionProvider;
|
||||
|
||||
/**
|
||||
* The server environment for retrieving configuration.
|
||||
*/
|
||||
@Inject
|
||||
private JDBCEnvironment environment;
|
||||
|
||||
/**
|
||||
* 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
|
||||
if (user.isPrivileged() || user.getUser().getEffectivePermissions().getSystemPermissions().hasPermission(SystemPermission.Type.AUDIT))
|
||||
searchResults = connectionRecordMapper.search(identifier,
|
||||
recordIdentifier, requiredContents, sortPredicates, limit);
|
||||
recordIdentifier, requiredContents, sortPredicates, limit,
|
||||
environment.getCaseSensitiveUsernames());
|
||||
|
||||
// Otherwise only return explicitly readable history records
|
||||
else
|
||||
searchResults = connectionRecordMapper.searchReadable(identifier,
|
||||
user.getUser().getModel(), recordIdentifier,
|
||||
requiredContents, sortPredicates, limit,
|
||||
user.getEffectiveUserGroups());
|
||||
user.getEffectiveUserGroups(),
|
||||
environment.getCaseSensitiveUsernames());
|
||||
|
||||
return getObjectInstances(searchResults);
|
||||
|
||||
|
@@ -19,7 +19,142 @@
|
||||
|
||||
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.
|
||||
*/
|
||||
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);
|
||||
|
||||
}
|
||||
|
@@ -131,16 +131,21 @@ public class PasswordPolicyService {
|
||||
* @return
|
||||
* true if the given password matches any of the user's previous
|
||||
* 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,
|
||||
int historySize) {
|
||||
int historySize) throws GuacamoleException {
|
||||
|
||||
// No need to compare if no history is relevant
|
||||
if (historySize <= 0)
|
||||
return false;
|
||||
|
||||
// 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) {
|
||||
|
||||
byte[] hash = encryptionService.createPasswordHash(password, record.getPasswordSalt());
|
||||
|
@@ -34,6 +34,7 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
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.connection.ModeledConnection;
|
||||
import org.apache.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
|
||||
@@ -167,6 +168,12 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
|
||||
*/
|
||||
@Inject
|
||||
private SharedConnectionMap connectionMap;
|
||||
|
||||
/**
|
||||
* The Guacamole server environment.
|
||||
*/
|
||||
@Inject
|
||||
private JDBCEnvironment environment;
|
||||
|
||||
/**
|
||||
* All active connections through the tunnel having a given UUID.
|
||||
@@ -470,7 +477,9 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
|
||||
// Record new active connection
|
||||
Runnable cleanupTask = new ConnectionCleanupTask(activeConnection);
|
||||
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);
|
||||
}
|
||||
|
||||
|
@@ -194,5 +194,10 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser {
|
||||
public boolean isPrivileged() throws GuacamoleException {
|
||||
return getUser().isPrivileged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCaseSensitive() {
|
||||
return user.isCaseSensitive();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -36,6 +36,7 @@ import java.util.TimeZone;
|
||||
import org.apache.guacamole.auth.jdbc.security.PasswordEncryptionService;
|
||||
import org.apache.guacamole.auth.jdbc.security.SaltService;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
|
||||
import org.apache.guacamole.form.BooleanField;
|
||||
import org.apache.guacamole.form.DateField;
|
||||
@@ -180,6 +181,13 @@ public class ModeledUser extends ModeledPermissions<UserModel> implements User {
|
||||
*/
|
||||
@Inject
|
||||
private Provider<UserRecordSet> userRecordSetProvider;
|
||||
|
||||
/**
|
||||
* The environment associated with this instance of the JDBC authentication
|
||||
* module.
|
||||
*/
|
||||
@Inject
|
||||
private JDBCEnvironment environment;
|
||||
|
||||
/**
|
||||
* Whether attributes which control access restrictions should be exposed
|
||||
@@ -780,5 +788,18 @@ public class ModeledUser extends ModeledPermissions<UserModel> implements User {
|
||||
public boolean isSkeleton() {
|
||||
return (getModel().getEntityID() == null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCaseSensitive() {
|
||||
try {
|
||||
return environment.getCaseSensitiveUsernames();
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -176,8 +176,12 @@ public class ModeledUserContext extends RestrictedObject
|
||||
* invocation has any effect. If this function is never invoked, no
|
||||
* activity record will be recorded, including when this UserContext is
|
||||
* 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
|
||||
if (userRecord != null)
|
||||
@@ -190,7 +194,7 @@ public class ModeledUserContext extends RestrictedObject
|
||||
userRecord.setRemoteHost(getCurrentUser().getCredentials().getRemoteAddress());
|
||||
|
||||
// Insert record representing login
|
||||
userRecordMapper.insert(userRecord);
|
||||
userRecordMapper.insert(userRecord, environment.getCaseSensitiveUsernames());
|
||||
|
||||
}
|
||||
|
||||
|
@@ -38,6 +38,10 @@ public interface PasswordRecordMapper extends ModeledDirectoryObjectMapper<UserM
|
||||
*
|
||||
* @param maxHistorySize
|
||||
* 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
|
||||
* A collection of all password records associated with the user having
|
||||
@@ -45,7 +49,8 @@ public interface PasswordRecordMapper extends ModeledDirectoryObjectMapper<UserM
|
||||
* exists.
|
||||
*/
|
||||
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
|
||||
|
@@ -19,6 +19,7 @@
|
||||
|
||||
package org.apache.guacamole.auth.jdbc.user;
|
||||
|
||||
import java.util.Collection;
|
||||
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
@@ -33,10 +34,82 @@ public interface UserMapper extends ModeledDirectoryObjectMapper<UserModel> {
|
||||
*
|
||||
* @param username
|
||||
* The username of the user to return.
|
||||
*
|
||||
* @param caseSensitive
|
||||
* true if the search should evaluate usernames in a case-sensitive
|
||||
* manner, otherwise false.
|
||||
*
|
||||
* @return
|
||||
* 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);
|
||||
|
||||
}
|
||||
|
@@ -33,6 +33,7 @@ import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectService;
|
||||
import org.apache.guacamole.GuacamoleClientException;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
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.ActivityRecordSearchTerm;
|
||||
import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
|
||||
@@ -155,6 +156,12 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
||||
*/
|
||||
@Inject
|
||||
private PasswordPolicyService passwordPolicyService;
|
||||
|
||||
/**
|
||||
* The server environment for retrieving configuration.
|
||||
*/
|
||||
@Inject
|
||||
private JDBCEnvironment environment;
|
||||
|
||||
@Override
|
||||
protected ModeledDirectoryObjectMapper<UserModel> getObjectMapper() {
|
||||
@@ -241,7 +248,8 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
||||
throw new GuacamoleClientException("The username must not be blank.");
|
||||
|
||||
// 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())
|
||||
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.");
|
||||
|
||||
// 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) {
|
||||
|
||||
// Do not rename to existing user
|
||||
@@ -337,6 +346,17 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
||||
throw new GuacamoleUnsupportedException("Deleting your own user is not allowed.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteObject(ModeledAuthenticatedUser user, String identifier)
|
||||
throws GuacamoleException {
|
||||
|
||||
beforeDelete(user, identifier);
|
||||
|
||||
// Delete object
|
||||
userMapper.delete(identifier, environment.getCaseSensitiveUsernames());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isValidIdentifier(String identifier) {
|
||||
@@ -375,7 +395,8 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
||||
String password = credentials.getPassword();
|
||||
|
||||
// Retrieve corresponding user model, if such a user exists
|
||||
UserModel userModel = userMapper.selectOne(username);
|
||||
UserModel userModel = userMapper.selectOne(username,
|
||||
environment.getCaseSensitiveUsernames());
|
||||
if (userModel == null)
|
||||
return null;
|
||||
|
||||
@@ -416,7 +437,8 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
|
||||
AuthenticatedUser authenticatedUser) throws GuacamoleException {
|
||||
|
||||
// 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)
|
||||
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
|
||||
if (user.isPrivileged() || user.getUser().getEffectivePermissions().getSystemPermissions().hasPermission(SystemPermission.Type.AUDIT))
|
||||
searchResults = userRecordMapper.search(username, recordIdentifier,
|
||||
requiredContents, sortPredicates, limit);
|
||||
requiredContents, sortPredicates, limit,
|
||||
environment.getCaseSensitiveUsernames());
|
||||
|
||||
// Otherwise only return explicitly readable history records
|
||||
else
|
||||
searchResults = userRecordMapper.searchReadable(username,
|
||||
user.getUser().getModel(), recordIdentifier,
|
||||
requiredContents, sortPredicates, limit,
|
||||
user.getEffectiveUserGroups());
|
||||
user.getEffectiveUserGroups(),
|
||||
environment.getCaseSensitiveUsernames());
|
||||
|
||||
return getObjectInstances(searchResults);
|
||||
|
||||
|
@@ -19,10 +19,67 @@
|
||||
|
||||
package org.apache.guacamole.auth.jdbc.usergroup;
|
||||
|
||||
import java.util.Collection;
|
||||
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
|
||||
* 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);
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user