Skip to content

Commit

Permalink
GUACAMOLE-1239: Add case-sensitivity settings to permissions mappers …
Browse files Browse the repository at this point in the history
…and services.
  • Loading branch information
necouchman committed Oct 12, 2024
1 parent 3fcc59a commit 61f6c8c
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 150 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ public InternalType createObject(ModeledAuthenticatedUser user, ExternalType obj
// Add implicit permissions
Collection<ObjectPermissionModel> implicitPermissions = getImplicitPermissions(user, model);
if (!implicitPermissions.isEmpty())
getPermissionMapper().insert(implicitPermissions);
getPermissionMapper().insert(implicitPermissions, getCaseSensitiveIdentifiers());

// Add any arbitrary attributes
if (model.hasArbitraryAttributes())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
public abstract class AbstractPermissionService<PermissionSetType extends PermissionSet<PermissionType>,
PermissionType extends Permission>
implements PermissionService<PermissionSetType, PermissionType> {

/**
* Returns the ObjectPermissionSet related to the type of the given entity.
* If the given entity represents a user, then the ObjectPermissionSet
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,12 @@ public void createPermissions(ModeledAuthenticatedUser user,
// Create permissions only if user has permission to do so
if (canAlterPermissions(user, targetEntity, permissions)) {

boolean caseSensitive = getCaseSensitiveIdentifiers();

batchPermissionUpdates(permissions, permissionSubset -> {
Collection<ObjectPermissionModel> models = getModelInstances(
targetEntity, permissionSubset);
getPermissionMapper().insert(models);
getPermissionMapper().insert(models, caseSensitive);
});

return;
Expand All @@ -156,10 +158,12 @@ public void deletePermissions(ModeledAuthenticatedUser user,
// Delete permissions only if user has permission to do so
if (canAlterPermissions(user, targetEntity, permissions)) {

boolean caseSensitive = getCaseSensitiveIdentifiers();

batchPermissionUpdates(permissions, permissionSubset -> {
Collection<ObjectPermissionModel> models = getModelInstances(
targetEntity, permissionSubset);
getPermissionMapper().delete(models);
getPermissionMapper().delete(models, caseSensitive);
});

return;
Expand All @@ -179,7 +183,7 @@ public boolean hasPermission(ModeledAuthenticatedUser user,
// Retrieve permissions only if allowed
if (canReadPermissions(user, targetEntity))
return getPermissionMapper().selectOne(targetEntity.getModel(),
type, identifier, effectiveGroups) != null;
type, identifier, effectiveGroups, getCaseSensitiveIdentifiers()) != null;

// User cannot read this entity's permissions
throw new GuacamoleSecurityException("Permission denied.");
Expand All @@ -205,7 +209,7 @@ public Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser
if (canReadPermissions(user, targetEntity))
return getPermissionMapper().selectAccessibleIdentifiers(
targetEntity.getModel(), permissions, identifiers,
effectiveGroups);
effectiveGroups, getCaseSensitiveIdentifiers());

// User cannot read this entity's permissions
throw new GuacamoleSecurityException("Permission denied.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,10 @@ public Set<PermissionType> retrievePermissions(ModeledAuthenticatedUser user,

// Retrieve permissions only if allowed
if (canReadPermissions(user, targetEntity))
return getPermissionInstances(getPermissionMapper().select(targetEntity.getModel(), effectiveGroups));
return getPermissionInstances(getPermissionMapper().select(
targetEntity.getModel(),
effectiveGroups,
getCaseSensitiveIdentifiers()));

// User cannot read this entity's permissions
throw new GuacamoleSecurityException("Permission denied.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ public interface ObjectPermissionMapper extends PermissionMapper<ObjectPermissio
* 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
* "true" if identifiers should be treated as case-sensitive, otherwise
* "false".
*
* @return
* The requested permission, or null if no such permission is granted
Expand All @@ -56,7 +60,8 @@ public interface ObjectPermissionMapper extends PermissionMapper<ObjectPermissio
ObjectPermissionModel selectOne(@Param("entity") EntityModel entity,
@Param("type") ObjectPermission.Type type,
@Param("identifier") String identifier,
@Param("effectiveGroups") Collection<String> effectiveGroups);
@Param("effectiveGroups") Collection<String> effectiveGroups,
@Param("caseSensitive") boolean caseSensitive);

/**
* Retrieves the subset of the given identifiers for which the given entity
Expand All @@ -79,6 +84,10 @@ ObjectPermissionModel selectOne(@Param("entity") EntityModel entity,
* 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
* "true" if identifiers should be treated as case-sensitive, otherwise
* "false".
*
* @return
* A collection containing the subset of identifiers for which at least
Expand All @@ -87,6 +96,7 @@ ObjectPermissionModel selectOne(@Param("entity") EntityModel entity,
Collection<String> selectAccessibleIdentifiers(@Param("entity") EntityModel entity,
@Param("permissions") Collection<ObjectPermission.Type> permissions,
@Param("identifiers") Collection<String> identifiers,
@Param("effectiveGroups") Collection<String> effectiveGroups);
@Param("effectiveGroups") Collection<String> effectiveGroups,
@Param("caseSensitive") boolean caseSensitive);

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,35 +43,50 @@ public interface PermissionMapper<PermissionType> {
* 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
* "true" if identifiers should be treated as case-sensitive, otherwise
* "false".
*
* @return
* All permissions associated with the given entity.
*/
Collection<PermissionType> select(@Param("entity") EntityModel entity,
@Param("effectiveGroups") Collection<String> effectiveGroups);
@Param("effectiveGroups") Collection<String> effectiveGroups,
@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
* "true" if identifiers should be treated as case-sensitive, otherwise
* "false".
*
* @return
* The number of rows inserted.
*/
int insert(@Param("permissions") Collection<PermissionType> permissions);
int insert(@Param("permissions") Collection<PermissionType> permissions,
@Param("caseSensitive") boolean caseSensitive);

/**
* 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
* "true" if identifiers should be treated as case-sensitive, otherwise
* "false".
*
* @return
* The number of rows deleted.
*/
int delete(@Param("permissions") Collection<PermissionType> permissions);
int delete(@Param("permissions") Collection<PermissionType> permissions,
@Param("caseSensitive") boolean caseSensitive);

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,24 @@
public interface PermissionService<PermissionSetType extends PermissionSet<PermissionType>,
PermissionType extends Permission> {

/**
* Return "true" if identifiers should be treated as case-sensitive,
* otherwise "false".
*
* @return
* "true" if identifiers should be treated as case-sensitive, otherwise
* "false".
*
* @throws GuacamoleException
* If an error occurs retrieving configuration information related to
* case-sensitivity.
*/
default boolean getCaseSensitiveIdentifiers() throws GuacamoleException {

// By default identifiers are case-insensitive.
return false;
}

/**
* Returns a permission set that can be used to retrieve and manipulate the
* permissions of the given entity.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,13 @@ public void createPermissions(ModeledAuthenticatedUser user,
// system permissions
if (user.isPrivileged()) {

// Pull identifier case sensitivity
boolean caseSensitive = getCaseSensitiveIdentifiers();

batchPermissionUpdates(permissions, permissionSubset -> {
Collection<SystemPermissionModel> models = getModelInstances(
targetEntity, permissionSubset);
systemPermissionMapper.insert(models);
systemPermissionMapper.insert(models, caseSensitive);
});

return;
Expand All @@ -125,10 +128,13 @@ public void deletePermissions(ModeledAuthenticatedUser user,
if (user.getUser().getIdentifier().equals(targetEntity.getIdentifier()))
throw new GuacamoleUnsupportedException("Removing your own administrative permissions is not allowed.");

// Pull case sensitivity
boolean caseSensitive = getCaseSensitiveIdentifiers();

batchPermissionUpdates(permissions, permissionSubset -> {
Collection<SystemPermissionModel> models = getModelInstances(
targetEntity, permissionSubset);
systemPermissionMapper.delete(models);
systemPermissionMapper.delete(models, caseSensitive);
});

return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,142 +19,7 @@

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 {

/**
* 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("caseSensitive") boolean caseSensitive);

}
public interface UserPermissionMapper extends ObjectPermissionMapper {}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.Set;
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
import org.apache.guacamole.auth.jdbc.base.EntityModel;
import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;

Expand All @@ -46,6 +47,17 @@ public class UserPermissionService extends ModeledObjectPermissionService {
@Inject
private Provider<UserPermissionSet> userPermissionSetProvider;

/**
* The server environment for retrieving configuration data.
*/
@Inject
private JDBCEnvironment environment;

@Override
public boolean getCaseSensitiveIdentifiers() throws GuacamoleException {
return environment.getCaseSensitiveUsernames();
}

@Override
protected ObjectPermissionMapper getPermissionMapper() {
return userPermissionMapper;
Expand Down

0 comments on commit 61f6c8c

Please sign in to comment.