mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
GUAC-1126: Allow non-admins to see active connections if they have READ permission to those connections.
This commit is contained in:
@@ -88,20 +88,22 @@ public class ActiveConnectionPermissionService
|
||||
if (canReadPermissions(user, targetUser)) {
|
||||
|
||||
// Only administrators may access active connections
|
||||
if (!targetUser.isAdministrator())
|
||||
return Collections.EMPTY_SET;
|
||||
boolean isAdmin = targetUser.isAdministrator();
|
||||
|
||||
// Get all active connections
|
||||
Collection<ActiveConnectionRecord> records = tunnelService.getActiveConnections(user);
|
||||
|
||||
// We have READ and DELETE on all active connections
|
||||
// We have READ, and possibly DELETE, on all active connections
|
||||
Set<ObjectPermission> permissions = new HashSet<ObjectPermission>();
|
||||
for (ActiveConnectionRecord record : records) {
|
||||
|
||||
// Add implicit READ and DELETE
|
||||
// Add implicit READ
|
||||
String identifier = record.getUUID().toString();
|
||||
permissions.add(new ObjectPermission(ObjectPermission.Type.READ, identifier));
|
||||
permissions.add(new ObjectPermission(ObjectPermission.Type.DELETE, identifier));
|
||||
permissions.add(new ObjectPermission(ObjectPermission.Type.READ, identifier));
|
||||
|
||||
// If we're and admin, then we also have DELETE
|
||||
if (isAdmin)
|
||||
permissions.add(new ObjectPermission(ObjectPermission.Type.DELETE, identifier));
|
||||
|
||||
}
|
||||
|
||||
|
@@ -26,6 +26,7 @@ import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
|
||||
@@ -62,35 +63,42 @@ public class ActiveConnectionService
|
||||
public TrackedActiveConnection retrieveObject(AuthenticatedUser user,
|
||||
String identifier) throws GuacamoleException {
|
||||
|
||||
// Only administrators may retrieve active connections
|
||||
if (!user.getUser().isAdministrator())
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
// Pull objects having given identifier
|
||||
Collection<TrackedActiveConnection> objects = retrieveObjects(user, Collections.singleton(identifier));
|
||||
|
||||
// Retrieve record associated with requested connection
|
||||
ActiveConnectionRecord record = tunnelService.getActiveConnection(user, identifier);
|
||||
if (record == null)
|
||||
// If no such object, return null
|
||||
if (objects.isEmpty())
|
||||
return null;
|
||||
|
||||
// Return tracked active connection using retrieved record
|
||||
TrackedActiveConnection activeConnection = trackedActiveConnectionProvider.get();
|
||||
activeConnection.init(user, record);
|
||||
return activeConnection;
|
||||
|
||||
// The object collection will have exactly one element unless the
|
||||
// database has seriously lost integrity
|
||||
assert(objects.size() == 1);
|
||||
|
||||
// Return first and only object
|
||||
return objects.iterator().next();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<TrackedActiveConnection> retrieveObjects(AuthenticatedUser user,
|
||||
Collection<String> identifiers) throws GuacamoleException {
|
||||
|
||||
// Build list of all active connections with given identifiers
|
||||
Collection<TrackedActiveConnection> activeConnections = new ArrayList<TrackedActiveConnection>(identifiers.size());
|
||||
for (String identifier : identifiers) {
|
||||
Set<String> identifierSet = new HashSet<String>(identifiers);
|
||||
|
||||
// Add connection to list if it exists
|
||||
TrackedActiveConnection activeConnection = retrieveObject(user, identifier);
|
||||
if (activeConnection != null)
|
||||
// Retrieve all visible connections (permissions enforced by tunnel service)
|
||||
Collection<ActiveConnectionRecord> records = tunnelService.getActiveConnections(user);
|
||||
|
||||
// Restrict to subset of records which match given identifiers
|
||||
Collection<TrackedActiveConnection> activeConnections = new ArrayList<TrackedActiveConnection>(identifiers.size());
|
||||
for (ActiveConnectionRecord record : records) {
|
||||
|
||||
// Add connection if within requested identifiers
|
||||
if (identifierSet.contains(record.getUUID().toString())) {
|
||||
TrackedActiveConnection activeConnection = trackedActiveConnectionProvider.get();
|
||||
activeConnection.init(user, record);
|
||||
activeConnections.add(activeConnection);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return activeConnections;
|
||||
@@ -101,6 +109,10 @@ public class ActiveConnectionService
|
||||
public void deleteObject(AuthenticatedUser user, String identifier)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Only administrators may delete active connections
|
||||
if (!user.getUser().isAdministrator())
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
// Close connection, if it exists (and we have permission)
|
||||
ActiveConnection activeConnection = retrieveObject(user, identifier);
|
||||
if (activeConnection != null) {
|
||||
|
@@ -28,8 +28,10 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
|
||||
@@ -448,24 +450,33 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
|
||||
public Collection<ActiveConnectionRecord> getActiveConnections(AuthenticatedUser user)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Only administrators may see all active connections
|
||||
if (!user.getUser().isAdministrator())
|
||||
// Simply return empty list if there are no active tunnels
|
||||
Collection<ActiveConnectionRecord> records = activeTunnels.values();
|
||||
if (records.isEmpty())
|
||||
return Collections.EMPTY_LIST;
|
||||
|
||||
return Collections.unmodifiableCollection(activeTunnels.values());
|
||||
// Build set of all connection identifiers associated with active tunnels
|
||||
Set<String> identifiers = new HashSet<String>(records.size());
|
||||
for (ActiveConnectionRecord record : records)
|
||||
identifiers.add(record.getConnection().getIdentifier());
|
||||
|
||||
}
|
||||
// Produce collection of readable connection identifiers
|
||||
Collection<ConnectionModel> connections = connectionMapper.selectReadable(user.getUser().getModel(), identifiers);
|
||||
|
||||
@Override
|
||||
public ActiveConnectionRecord getActiveConnection(AuthenticatedUser user,
|
||||
String tunnelUUID) throws GuacamoleException {
|
||||
// Ensure set contains only identifiers of readable connections
|
||||
identifiers.clear();
|
||||
for (ConnectionModel connection : connections)
|
||||
identifiers.add(connection.getIdentifier());
|
||||
|
||||
// Only administrators may see all active connections
|
||||
if (!user.getUser().isAdministrator())
|
||||
return null;
|
||||
// Produce readable subset of records
|
||||
Collection<ActiveConnectionRecord> visibleRecords = new ArrayList<ActiveConnectionRecord>(records.size());
|
||||
for (ActiveConnectionRecord record : records) {
|
||||
if (identifiers.contains(record.getConnection().getIdentifier()))
|
||||
visibleRecords.add(record);
|
||||
}
|
||||
|
||||
return visibleRecords;
|
||||
|
||||
return activeTunnels.get(tunnelUUID);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -59,30 +59,6 @@ public interface GuacamoleTunnelService {
|
||||
public Collection<ActiveConnectionRecord> getActiveConnections(AuthenticatedUser user)
|
||||
throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns the connection records representing the connection associated
|
||||
* with the tunnel having the given UUID, if that connection is visible to
|
||||
* the given user.
|
||||
*
|
||||
* @param user
|
||||
* The user retrieving the active connection.
|
||||
*
|
||||
* @param tunnelUUID
|
||||
* The UUID of the tunnel associated with the active connection being
|
||||
* retrieved.
|
||||
*
|
||||
* @return
|
||||
* The active connection associated with the tunnel having the given
|
||||
* UUID, or null if no such connection exists.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If an error occurs while retrieving all active connections, or if
|
||||
* permission is denied.
|
||||
*/
|
||||
public ActiveConnectionRecord getActiveConnection(AuthenticatedUser user,
|
||||
String tunnelUUID)
|
||||
throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Creates a socket for the given user which connects to the given
|
||||
* connection. The given client information will be passed to guacd when
|
||||
|
Reference in New Issue
Block a user