diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java index d5af87794..386df9bb9 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java @@ -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 records = tunnelService.getActiveConnections(user); - // We have READ and DELETE on all active connections + // We have READ, and possibly DELETE, on all active connections Set permissions = new HashSet(); 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)); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/ActiveConnectionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/ActiveConnectionService.java index 41eceef60..27b7f4723 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/ActiveConnectionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/ActiveConnectionService.java @@ -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 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 retrieveObjects(AuthenticatedUser user, Collection identifiers) throws GuacamoleException { - // Build list of all active connections with given identifiers - Collection activeConnections = new ArrayList(identifiers.size()); - for (String identifier : identifiers) { + Set identifierSet = new HashSet(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 records = tunnelService.getActiveConnections(user); + + // Restrict to subset of records which match given identifiers + Collection activeConnections = new ArrayList(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) { diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java index 10adde197..bfa6231e3 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java @@ -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 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 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 identifiers = new HashSet(records.size()); + for (ActiveConnectionRecord record : records) + identifiers.add(record.getConnection().getIdentifier()); - } + // Produce collection of readable connection identifiers + Collection 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 visibleRecords = new ArrayList(records.size()); + for (ActiveConnectionRecord record : records) { + if (identifiers.contains(record.getConnection().getIdentifier())) + visibleRecords.add(record); + } + + return visibleRecords; - return activeTunnels.get(tunnelUUID); - } @Override diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/GuacamoleTunnelService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/GuacamoleTunnelService.java index 0bb78419d..c965a823b 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/GuacamoleTunnelService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/GuacamoleTunnelService.java @@ -59,30 +59,6 @@ public interface GuacamoleTunnelService { public Collection 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 diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/activeconnection/ActiveConnectionRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/activeconnection/ActiveConnectionRESTService.java index 7553db7ad..1a47582bc 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/activeconnection/ActiveConnectionRESTService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/activeconnection/ActiveConnectionRESTService.java @@ -106,14 +106,14 @@ public class ActiveConnectionRESTService { if (permissions != null && permissions.isEmpty()) permissions = null; - // An admin user has access to any user + // An admin user has access to any connection SystemPermissionSet systemPermissions = self.getSystemPermissions(); boolean isAdmin = systemPermissions.hasPermission(SystemPermission.Type.ADMINISTER); // Get the directory Directory activeConnectionDirectory = userContext.getActiveConnectionDirectory(); - // Filter users, if requested + // Filter connections, if requested Collection activeConnectionIdentifiers = activeConnectionDirectory.getIdentifiers(); if (!isAdmin && permissions != null) { ObjectPermissionSet activeConnectionPermissions = self.getActiveConnectionPermissions();