GUAC-1126: Allow non-admins to see active connections if they have READ permission to those connections.

This commit is contained in:
Michael Jumper
2015-04-09 14:15:55 -07:00
parent 311d56bae5
commit f8714b735f
5 changed files with 63 additions and 62 deletions

View File

@@ -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));
}

View File

@@ -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) {

View File

@@ -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

View File

@@ -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