mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
GUAC-1101: Limit results of retrieval operations by read permissions, unless user is a sysadmin.
This commit is contained in:
@@ -29,6 +29,7 @@ import net.sourceforge.guacamole.net.auth.mysql.service.SaltService;
|
|||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
import org.glyptodon.guacamole.net.auth.User;
|
import org.glyptodon.guacamole.net.auth.User;
|
||||||
import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
|
import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||||
|
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
|
||||||
import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
|
import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
|
||||||
import org.glyptodon.guacamole.net.auth.simple.SimpleObjectPermissionSet;
|
import org.glyptodon.guacamole.net.auth.simple.SimpleObjectPermissionSet;
|
||||||
import org.glyptodon.guacamole.net.auth.simple.SimpleSystemPermissionSet;
|
import org.glyptodon.guacamole.net.auth.simple.SimpleSystemPermissionSet;
|
||||||
@@ -126,6 +127,22 @@ public class MySQLUser implements User, DirectoryObject<UserModel> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether this user is a system administrator, and thus is not
|
||||||
|
* restricted by permissions.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* true if this user is a system administrator, false otherwise.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If an error occurs while determining the user's system administrator
|
||||||
|
* status.
|
||||||
|
*/
|
||||||
|
public boolean isAdministrator() throws GuacamoleException {
|
||||||
|
SystemPermissionSet systemPermissionSet = getSystemPermissions();
|
||||||
|
return systemPermissionSet.hasPermission(SystemPermission.Type.ADMINISTER);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SystemPermissionSet getSystemPermissions()
|
public SystemPermissionSet getSystemPermissions()
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
@@ -24,6 +24,7 @@ package net.sourceforge.guacamole.net.auth.mysql.dao;
|
|||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import net.sourceforge.guacamole.net.auth.mysql.model.UserModel;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,23 +33,45 @@ import org.apache.ibatis.annotations.Param;
|
|||||||
* to fulfill the needs of the Directory class.
|
* to fulfill the needs of the Directory class.
|
||||||
*
|
*
|
||||||
* @author Michael Jumper
|
* @author Michael Jumper
|
||||||
* @param <T>
|
* @param <ModelType>
|
||||||
* The type of object contained within the directory whose objects are
|
* The type of object contained within the directory whose objects are
|
||||||
* mapped by this mapper.
|
* mapped by this mapper.
|
||||||
*/
|
*/
|
||||||
public interface DirectoryObjectMapper<T> {
|
public interface DirectoryObjectMapper<ModelType> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects the identifiers of all objects.
|
* Selects the identifiers of all objects, regardless of whether they
|
||||||
|
* are readable by any particular user. This should only be called on
|
||||||
|
* behalf of a system administrator. If identifiers are needed by a non-
|
||||||
|
* administrative user who must have explicit read rights, use
|
||||||
|
* selectReadableIdentifiers() instead.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* A Set containing all identifiers of all objects.
|
* A Set containing all identifiers of all objects.
|
||||||
*/
|
*/
|
||||||
Set<String> selectIdentifiers();
|
Set<String> selectIdentifiers();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects the identifiers of all objects that are explicitly readable by
|
||||||
|
* the given user. If identifiers are needed by a system administrator
|
||||||
|
* (who, by definition, does not need explicit read rights), use
|
||||||
|
* selectIdentifiers() instead.
|
||||||
|
*
|
||||||
|
* @param user
|
||||||
|
* The user whose permissions should determine whether an identifier
|
||||||
|
* is returned.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A Set containing all identifiers of all readable objects.
|
||||||
|
*/
|
||||||
|
Set<String> selectReadableIdentifiers(@Param("user") UserModel user);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Selects all objects which have the given identifiers. If an identifier
|
* Selects all objects which have the given identifiers. If an identifier
|
||||||
* has no corresponding object, it will be ignored.
|
* has no corresponding object, it will be ignored. This should only be
|
||||||
|
* called on behalf of a system administrator. If objects are needed by a
|
||||||
|
* non-administrative user who must have explicit read rights, use
|
||||||
|
* selectReadable() instead.
|
||||||
*
|
*
|
||||||
* @param identifiers
|
* @param identifiers
|
||||||
* The identifiers of the objects to return.
|
* The identifiers of the objects to return.
|
||||||
@@ -56,7 +79,27 @@ public interface DirectoryObjectMapper<T> {
|
|||||||
* @return
|
* @return
|
||||||
* A Collection of all objects having the given identifiers.
|
* A Collection of all objects having the given identifiers.
|
||||||
*/
|
*/
|
||||||
Collection<T> select(@Param("identifiers") Collection<String> identifiers);
|
Collection<ModelType> select(@Param("identifiers") Collection<String> identifiers);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Selects all objects which have the given identifiers and are explicitly
|
||||||
|
* readably by the given user. If an identifier has no corresponding
|
||||||
|
* object, or the corresponding object is unreadable, it will be ignored.
|
||||||
|
* If objects 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 objects to return.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* A Collection of all objects having the given identifiers.
|
||||||
|
*/
|
||||||
|
Collection<ModelType> selectReadable(@Param("user") UserModel user,
|
||||||
|
@Param("identifiers") Collection<String> identifiers);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts the given object into the database. If the object already
|
* Inserts the given object into the database. If the object already
|
||||||
@@ -68,7 +111,7 @@ public interface DirectoryObjectMapper<T> {
|
|||||||
* @return
|
* @return
|
||||||
* The number of rows inserted.
|
* The number of rows inserted.
|
||||||
*/
|
*/
|
||||||
int insert(@Param("object") T object);
|
int insert(@Param("object") ModelType object);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the given object into the database. If the object does not
|
* Deletes the given object into the database. If the object does not
|
||||||
@@ -92,6 +135,6 @@ public interface DirectoryObjectMapper<T> {
|
|||||||
* @return
|
* @return
|
||||||
* The number of rows updated.
|
* The number of rows updated.
|
||||||
*/
|
*/
|
||||||
int update(@Param("object") T object);
|
int update(@Param("object") ModelType object);
|
||||||
|
|
||||||
}
|
}
|
@@ -103,9 +103,12 @@ public abstract class DirectoryObjectService<ObjectType extends DirectoryObject<
|
|||||||
* @return
|
* @return
|
||||||
* The object having the given identifier, or null if no such object
|
* The object having the given identifier, or null if no such object
|
||||||
* exists.
|
* exists.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If an error occurs while retrieving the requested object.
|
||||||
*/
|
*/
|
||||||
public ObjectType retrieveObject(AuthenticatedUser user,
|
public ObjectType retrieveObject(AuthenticatedUser user,
|
||||||
String identifier) {
|
String identifier) throws GuacamoleException {
|
||||||
|
|
||||||
// Pull objects having given identifier
|
// Pull objects having given identifier
|
||||||
Collection<ObjectType> objects = retrieveObjects(user, Collections.singleton(identifier));
|
Collection<ObjectType> objects = retrieveObjects(user, Collections.singleton(identifier));
|
||||||
@@ -135,16 +138,29 @@ public abstract class DirectoryObjectService<ObjectType extends DirectoryObject<
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* The objects having the given identifiers.
|
* The objects having the given identifiers.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If an error occurs while retrieving the requested objects.
|
||||||
*/
|
*/
|
||||||
public Collection<ObjectType> retrieveObjects(AuthenticatedUser user,
|
public Collection<ObjectType> retrieveObjects(AuthenticatedUser user,
|
||||||
Collection<String> identifiers) {
|
Collection<String> identifiers) throws GuacamoleException {
|
||||||
|
|
||||||
// Do not query if no identifiers given
|
// Do not query if no identifiers given
|
||||||
if (identifiers.isEmpty())
|
if (identifiers.isEmpty())
|
||||||
return Collections.EMPTY_LIST;
|
return Collections.EMPTY_LIST;
|
||||||
|
|
||||||
|
Collection<ModelType> objects;
|
||||||
|
|
||||||
|
// Bypass permission checks if the user is a system admin
|
||||||
|
if (user.getUser().isAdministrator())
|
||||||
|
objects = getObjectMapper().select(identifiers);
|
||||||
|
|
||||||
|
// Otherwise only return explicitly readable identifiers
|
||||||
|
else
|
||||||
|
objects = getObjectMapper().selectReadable(user.getUser().getModel(), identifiers);
|
||||||
|
|
||||||
// Return collection of requested objects
|
// Return collection of requested objects
|
||||||
return getObjectInstances(getObjectMapper().select(identifiers));
|
return getObjectInstances(objects);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,9 +231,21 @@ public abstract class DirectoryObjectService<ObjectType extends DirectoryObject<
|
|||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* The set of all identifiers for all objects in the database.
|
* The set of all identifiers for all objects in the database.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If an error occurs while reading identifiers.
|
||||||
*/
|
*/
|
||||||
public Set<String> getIdentifiers(AuthenticatedUser user) {
|
public Set<String> getIdentifiers(AuthenticatedUser user)
|
||||||
return getObjectMapper().selectIdentifiers();
|
throws GuacamoleException {
|
||||||
|
|
||||||
|
// Bypass permission checks if the user is a system admin
|
||||||
|
if (user.getUser().isAdministrator())
|
||||||
|
return getObjectMapper().selectIdentifiers();
|
||||||
|
|
||||||
|
// Otherwise only return explicitly readable identifiers
|
||||||
|
else
|
||||||
|
return getObjectMapper().selectReadableIdentifiers(user.getUser().getModel());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -40,6 +40,16 @@
|
|||||||
FROM guacamole_user
|
FROM guacamole_user
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<!-- Select usernames of all readable users -->
|
||||||
|
<select id="selectReadableIdentifiers" resultType="string">
|
||||||
|
SELECT username
|
||||||
|
FROM guacamole_user
|
||||||
|
JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
|
||||||
|
WHERE
|
||||||
|
guacamole_user_permission.user_id = #{user.userID,jdbcType=INTEGER}
|
||||||
|
AND permission = 'read'
|
||||||
|
</select>
|
||||||
|
|
||||||
<!-- Select multiple users by username -->
|
<!-- Select multiple users by username -->
|
||||||
<select id="select" resultMap="UserResultMap">
|
<select id="select" resultMap="UserResultMap">
|
||||||
|
|
||||||
@@ -57,6 +67,27 @@
|
|||||||
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<!-- Select multiple users by username only if readable -->
|
||||||
|
<select id="selectReadable" resultMap="UserResultMap">
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
guacamole_user.user_id,
|
||||||
|
username,
|
||||||
|
password_hash,
|
||||||
|
password_salt
|
||||||
|
FROM guacamole_user
|
||||||
|
JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
|
||||||
|
WHERE username IN
|
||||||
|
<foreach collection="identifiers" item="identifier"
|
||||||
|
open="(" separator="," close=")">
|
||||||
|
#{identifier,jdbcType=VARCHAR}
|
||||||
|
</foreach>
|
||||||
|
AND guacamole_user_permission.user_id = #{user.userID,jdbcType=INTEGER}
|
||||||
|
AND permission = 'read'
|
||||||
|
|
||||||
|
</select>
|
||||||
|
|
||||||
|
|
||||||
<select id="selectByCredentials" resultMap="UserResultMap">
|
<select id="selectByCredentials" resultMap="UserResultMap">
|
||||||
SELECT
|
SELECT
|
||||||
user_id,
|
user_id,
|
||||||
|
Reference in New Issue
Block a user