Skip to content
This repository has been archived by the owner on Jul 17, 2023. It is now read-only.

Commit

Permalink
GUAC-1101: Limit results of retrieval operations by read permissions,…
Browse files Browse the repository at this point in the history
… unless user is a sysadmin.
  • Loading branch information
mike-jumper committed Mar 1, 2015
1 parent b514fc9 commit 0e38acb
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 12 deletions.
Expand Up @@ -29,6 +29,7 @@
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;
Expand Down Expand Up @@ -126,6 +127,22 @@ public void setPassword(String password) {


} }


/**
* 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 {
Expand Down
Expand Up @@ -24,6 +24,7 @@


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;


/** /**
Expand All @@ -32,31 +33,73 @@
* 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
* The identifiers of the objects to return.
*
* @return
* A Collection of all objects having the given 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 * @param identifiers
* The identifiers of the objects to return. * The identifiers of the objects to return.
* *
* @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> 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
Expand All @@ -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
Expand All @@ -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);


} }
Expand Up @@ -103,9 +103,12 @@ protected Collection<ObjectType> getObjectInstances(Collection<ModelType> models
* @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));
Expand Down Expand Up @@ -135,16 +138,29 @@ public ObjectType retrieveObject(AuthenticatedUser user,
* *
* @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);


} }


Expand Down Expand Up @@ -215,9 +231,21 @@ public void updateObject(AuthenticatedUser user, ObjectType object)
* *
* @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());

} }


} }
Expand Up @@ -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">


Expand All @@ -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,
Expand Down

0 comments on commit 0e38acb

Please sign in to comment.