diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml index 40ca67bee..a5f808c53 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml @@ -37,6 +37,14 @@ + + + javax.servlet + servlet-api + 2.5 + provided + + org.glyptodon.guacamole diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java index a50389f48..a02012a90 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java @@ -40,7 +40,7 @@ import org.glyptodon.guacamole.auth.jdbc.permission.SystemPermissionMapper; import org.glyptodon.guacamole.auth.jdbc.user.UserMapper; import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ConnectionGroupService; import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionService; -import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService; +import org.glyptodon.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService; import org.glyptodon.guacamole.auth.jdbc.security.PasswordEncryptionService; import org.glyptodon.guacamole.auth.jdbc.security.SHA256PasswordEncryptionService; import org.glyptodon.guacamole.auth.jdbc.security.SaltService; @@ -80,7 +80,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule { * The service class to use to provide GuacamoleSockets for each * connection. */ - private final Class socketServiceClass; + private final Class tunnelServiceClass; /** * Creates a new JDBC authentication provider module that configures the @@ -90,13 +90,13 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule { * @param environment * The environment to use to configure injected classes. * - * @param socketServiceClass + * @param tunnelServiceClass * The socket service to use to provide sockets for connections. */ public JDBCAuthenticationProviderModule(Environment environment, - Class socketServiceClass) { + Class tunnelServiceClass) { this.environment = environment; - this.socketServiceClass = socketServiceClass; + this.tunnelServiceClass = tunnelServiceClass; } @Override @@ -147,7 +147,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule { bind(UserService.class); // Bind provided socket service - bind(GuacamoleSocketService.class).to(socketServiceClass); + bind(GuacamoleTunnelService.class).to(tunnelServiceClass); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionService.java index 8ac5d5da7..8386d1a6d 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionService.java @@ -33,14 +33,14 @@ import java.util.Map; import java.util.Set; import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectMapper; -import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService; +import org.glyptodon.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService; import org.glyptodon.guacamole.GuacamoleClientException; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleSecurityException; import org.glyptodon.guacamole.auth.jdbc.base.GroupedDirectoryObjectService; import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionPermissionMapper; import org.glyptodon.guacamole.auth.jdbc.permission.ObjectPermissionMapper; -import org.glyptodon.guacamole.net.GuacamoleSocket; +import org.glyptodon.guacamole.net.GuacamoleTunnel; import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionRecord; import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; @@ -88,10 +88,10 @@ public class ConnectionService extends GroupedDirectoryObjectService connectionProvider; /** - * Service for creating and tracking sockets. + * Service for creating and tracking tunnels. */ @Inject - private GuacamoleSocketService socketService; + private GuacamoleTunnelService tunnelService; @Override protected DirectoryObjectMapper getObjectMapper() { @@ -371,7 +371,7 @@ public class ConnectionService extends GroupedDirectoryObjectService models = connectionRecordMapper.select(identifier); // Get currently-active connections - List records = new ArrayList(socketService.getActiveConnections(connection)); + List records = new ArrayList(tunnelService.getActiveConnections(connection)); Collections.reverse(records); // Add past connections from model objects @@ -403,19 +403,19 @@ public class ConnectionService extends GroupedDirectoryObjectService private ConnectionService connectionService; /** - * Service for creating and tracking sockets. + * Service for creating and tracking tunnels. */ @Inject - private GuacamoleSocketService socketService; + private GuacamoleTunnelService tunnelService; /** * Provider for lazy-loaded, permission-controlled configurations. @@ -114,13 +114,13 @@ public class ModeledConnection extends GroupedDirectoryObject } @Override - public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException { + public GuacamoleTunnel connect(GuacamoleClientInformation info) throws GuacamoleException { return connectionService.connect(getCurrentUser(), this, info); } @Override public int getActiveConnections() { - return socketService.getActiveConnections(this).size(); + return tunnelService.getActiveConnections(this).size(); } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java index c86e46588..d00d19d13 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java @@ -24,6 +24,7 @@ package org.glyptodon.guacamole.auth.jdbc.connection; import java.util.Date; +import org.glyptodon.guacamole.net.GuacamoleTunnel; import org.glyptodon.guacamole.net.auth.ConnectionRecord; /** @@ -51,6 +52,11 @@ public class ModeledConnectionRecord implements ConnectionRecord { this.model = model; } + @Override + public String getIdentifier() { + return model.getConnectionIdentifier(); + } + @Override public Date getStartDate() { return model.getStartDate(); @@ -61,6 +67,11 @@ public class ModeledConnectionRecord implements ConnectionRecord { return model.getEndDate(); } + @Override + public String getRemoteHost() { + return null; + } + @Override public String getUsername() { return model.getUsername(); @@ -71,4 +82,9 @@ public class ModeledConnectionRecord implements ConnectionRecord { return false; } + @Override + public GuacamoleTunnel getTunnel() { + return null; + } + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java index bca97adb6..4fa9ef9c8 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java @@ -27,7 +27,7 @@ import com.google.inject.Provider; import java.util.Set; import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectMapper; -import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService; +import org.glyptodon.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService; import org.glyptodon.guacamole.GuacamoleClientException; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleSecurityException; @@ -35,7 +35,7 @@ import org.glyptodon.guacamole.GuacamoleUnsupportedException; import org.glyptodon.guacamole.auth.jdbc.base.GroupedDirectoryObjectService; import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionGroupPermissionMapper; import org.glyptodon.guacamole.auth.jdbc.permission.ObjectPermissionMapper; -import org.glyptodon.guacamole.net.GuacamoleSocket; +import org.glyptodon.guacamole.net.GuacamoleTunnel; import org.glyptodon.guacamole.net.auth.ConnectionGroup; import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet; @@ -71,10 +71,10 @@ public class ConnectionGroupService extends GroupedDirectoryObjectService connectionGroupProvider; /** - * Service for creating and tracking sockets. + * Service for creating and tracking tunnels. */ @Inject - private GuacamoleSocketService socketService; + private GuacamoleTunnelService tunnelService; @Override protected DirectoryObjectMapper getObjectMapper() { @@ -235,19 +235,19 @@ public class ConnectionGroupService extends GroupedDirectoryObjectService activeTunnels = + new ConcurrentHashMap(); + /** * All active connections to a connection having a given identifier. */ @@ -319,6 +328,7 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS String parentIdentifier = connection.getParentIdentifier(); // Release connection + activeTunnels.remove(activeConnection.getUUID().toString()); activeConnections.remove(identifier, activeConnection); activeConnectionGroups.remove(parentIdentifier, activeConnection); release(user, connection); @@ -335,7 +345,7 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS } /** - * Creates a socket for the given user which connects to the given + * Creates a tunnel for the given user which connects to the given * connection, which MUST already be acquired via acquire(). The given * client information will be passed to guacd when the connection is * established. @@ -343,25 +353,22 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS * The connection will be automatically released when it closes, or if it * fails to establish entirely. * - * @param user - * The user for whom the connection is being established. - * - * @param connection - * The connection the user is connecting to. + * @param activeConnection + * The active connection record of the connection in use. * * @param info * Information describing the Guacamole client connecting to the given * connection. * * @return - * A new GuacamoleSocket which is configured and connected to the given + * A new GuacamoleTunnel which is configured and connected to the given * connection. * * @throws GuacamoleException * If an error occurs while the connection is being established, or * while connection configuration information is being retrieved. */ - private GuacamoleSocket getGuacamoleSocket(ActiveConnectionRecord activeConnection, + private GuacamoleTunnel assignGuacamoleTunnel(ActiveConnectionRecord activeConnection, GuacamoleClientInformation info) throws GuacamoleException { @@ -369,16 +376,22 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS // Record new active connection Runnable cleanupTask = new ConnectionCleanupTask(activeConnection); + activeTunnels.put(activeConnection.getUUID().toString(), activeConnection); activeConnections.put(connection.getIdentifier(), activeConnection); activeConnectionGroups.put(connection.getParentIdentifier(), activeConnection); - // Return new socket try { - return new ConfiguredGuacamoleSocket( + + // Obtain socket which will automatically run the cleanup task + GuacamoleSocket socket = new ConfiguredGuacamoleSocket( getUnconfiguredGuacamoleSocket(cleanupTask), getGuacamoleConfiguration(activeConnection.getUser(), connection), info ); + + // Assign and return new tunnel + return activeConnection.assignGuacamoleTunnel(socket); + } // Execute cleanup if socket could not be created @@ -432,15 +445,39 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS } + @Override + public Collection getActiveConnections(AuthenticatedUser user) + throws GuacamoleException { + + // Only administrators may see all active connections + if (!user.getUser().isAdministrator()) + return Collections.EMPTY_LIST; + + return Collections.unmodifiableCollection(activeTunnels.values()); + + } + + @Override + public ConnectionRecord getActiveConnection(AuthenticatedUser user, + String tunnelUUID) throws GuacamoleException { + + // Only administrators may see all active connections + if (!user.getUser().isAdministrator()) + return null; + + return activeTunnels.get(tunnelUUID); + + } + @Override @Transactional - public GuacamoleSocket getGuacamoleSocket(final AuthenticatedUser user, + public GuacamoleTunnel getGuacamoleTunnel(final AuthenticatedUser user, final ModeledConnection connection, GuacamoleClientInformation info) throws GuacamoleException { // Acquire and connect to single connection acquire(user, Collections.singletonList(connection)); - return getGuacamoleSocket(new ActiveConnectionRecord(user, connection), info); + return assignGuacamoleTunnel(new ActiveConnectionRecord(user, connection), info); } @@ -451,7 +488,7 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS @Override @Transactional - public GuacamoleSocket getGuacamoleSocket(AuthenticatedUser user, + public GuacamoleTunnel getGuacamoleTunnel(AuthenticatedUser user, ModeledConnectionGroup connectionGroup, GuacamoleClientInformation info) throws GuacamoleException { @@ -465,7 +502,7 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS // Acquire and connect to any child ModeledConnection connection = acquire(user, connections); - return getGuacamoleSocket(new ActiveConnectionRecord(user, connectionGroup, connection), info); + return assignGuacamoleTunnel(new ActiveConnectionRecord(user, connectionGroup, connection), info); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ActiveConnectionMultimap.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ActiveConnectionMultimap.java similarity index 96% rename from extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ActiveConnectionMultimap.java rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ActiveConnectionMultimap.java index e20ed733f..a0590333d 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ActiveConnectionMultimap.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ActiveConnectionMultimap.java @@ -20,7 +20,7 @@ * THE SOFTWARE. */ -package org.glyptodon.guacamole.auth.jdbc.socket; +package org.glyptodon.guacamole.auth.jdbc.tunnel; import java.util.Collection; import java.util.Collections; @@ -63,7 +63,7 @@ public class ActiveConnectionMultimap { // Get set of active connection records, creating if necessary Set connections = records.get(identifier); if (connections == null) { - connections = Collections.newSetFromMap(new LinkedHashMap()); + connections = Collections.synchronizedSet(Collections.newSetFromMap(new LinkedHashMap())); records.put(identifier, connections); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ActiveConnectionRecord.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ActiveConnectionRecord.java similarity index 74% rename from extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ActiveConnectionRecord.java rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ActiveConnectionRecord.java index 5d23a7443..de2bffaf2 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ActiveConnectionRecord.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ActiveConnectionRecord.java @@ -20,12 +20,16 @@ * THE SOFTWARE. */ -package org.glyptodon.guacamole.auth.jdbc.socket; +package org.glyptodon.guacamole.auth.jdbc.tunnel; import java.util.Date; +import java.util.UUID; import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection; import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; +import org.glyptodon.guacamole.net.AbstractGuacamoleTunnel; +import org.glyptodon.guacamole.net.GuacamoleSocket; +import org.glyptodon.guacamole.net.GuacamoleTunnel; import org.glyptodon.guacamole.net.auth.ConnectionRecord; @@ -61,6 +65,17 @@ public class ActiveConnectionRecord implements ConnectionRecord { */ private final Date startDate = new Date(); + /** + * The UUID that will be assigned to the underlying tunnel. + */ + private final UUID uuid = UUID.randomUUID(); + + /** + * The GuacamoleTunnel used by the connection associated with this + * connection record. + */ + private GuacamoleTunnel tunnel; + /** * Creates a new connection record associated with the given user, * connection, and balancing connection group. The given balancing @@ -148,6 +163,11 @@ public class ActiveConnectionRecord implements ConnectionRecord { public boolean hasBalancingGroup() { return balancingGroup != null; } + + @Override + public String getIdentifier() { + return connection.getIdentifier(); + } @Override public Date getStartDate() { @@ -162,6 +182,11 @@ public class ActiveConnectionRecord implements ConnectionRecord { } + @Override + public String getRemoteHost() { + return user.getRemoteHost(); + } + @Override public String getUsername() { return user.getUser().getIdentifier(); @@ -175,4 +200,54 @@ public class ActiveConnectionRecord implements ConnectionRecord { } + @Override + public GuacamoleTunnel getTunnel() { + return tunnel; + } + + /** + * Associates a new GuacamoleTunnel with this connection record using the + * given socket. + * + * @param socket + * The GuacamoleSocket to use to create the tunnel associated with this + * connection record. + * + * @return + * The newly-created tunnel associated with this connection record. + */ + public GuacamoleTunnel assignGuacamoleTunnel(final GuacamoleSocket socket) { + + // Create tunnel with given socket + this.tunnel = new AbstractGuacamoleTunnel() { + + @Override + public GuacamoleSocket getSocket() { + return socket; + } + + @Override + public UUID getUUID() { + return uuid; + } + + }; + + // Return newly-created tunnel + return this.tunnel; + + } + + /** + * Returns the UUID of the underlying tunnel. If there is no underlying + * tunnel, this will be the UUID assigned to the underlying tunnel when the + * tunnel is set. + * + * @return + * The current or future UUID of the underlying tunnel. + */ + public UUID getUUID() { + return uuid; + } + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/BalancedGuacamoleSocketService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/BalancedGuacamoleTunnelService.java similarity index 93% rename from extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/BalancedGuacamoleSocketService.java rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/BalancedGuacamoleTunnelService.java index 118c0cad9..b2cfcc8d1 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/BalancedGuacamoleSocketService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/BalancedGuacamoleTunnelService.java @@ -20,7 +20,7 @@ * THE SOFTWARE. */ -package org.glyptodon.guacamole.auth.jdbc.socket; +package org.glyptodon.guacamole.auth.jdbc.tunnel; import com.google.inject.Singleton; import java.util.Collections; @@ -35,7 +35,7 @@ import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; /** - * GuacamoleSocketService implementation which allows only one user per + * GuacamoleTunnelService implementation which allows only one user per * connection at any time, but does not disallow concurrent use of connection * groups. If a user attempts to use a connection group multiple times, they * will receive different underlying connections each time until the group is @@ -44,8 +44,8 @@ import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; * @author Michael Jumper */ @Singleton -public class BalancedGuacamoleSocketService - extends AbstractGuacamoleSocketService { +public class BalancedGuacamoleTunnelService + extends AbstractGuacamoleTunnelService { /** * The set of all active connection identifiers. diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/GuacamoleSocketService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/GuacamoleTunnelService.java similarity index 71% rename from extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/GuacamoleSocketService.java rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/GuacamoleTunnelService.java index e8daf4653..f45d31426 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/GuacamoleSocketService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/GuacamoleTunnelService.java @@ -20,14 +20,14 @@ * THE SOFTWARE. */ -package org.glyptodon.guacamole.auth.jdbc.socket; +package org.glyptodon.guacamole.auth.jdbc.tunnel; import java.util.Collection; import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection; import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; import org.glyptodon.guacamole.GuacamoleException; -import org.glyptodon.guacamole.net.GuacamoleSocket; +import org.glyptodon.guacamole.net.GuacamoleTunnel; import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionGroup; import org.glyptodon.guacamole.net.auth.ConnectionRecord; @@ -40,7 +40,49 @@ import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; * * @author Michael Jumper */ -public interface GuacamoleSocketService { +public interface GuacamoleTunnelService { + + /** + * Returns a collection containing connection records representing all + * currently-active connections visible by the given user. + * + * @param user + * The user retrieving active connections. + * + * @return + * A collection containing connection records representing all + * currently-active connections. + * + * @throws GuacamoleException + * If an error occurs while retrieving all active connections, or if + * permission is denied. + */ + 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 ConnectionRecord getActiveConnection(AuthenticatedUser user, + String tunnelUUID) + throws GuacamoleException; /** * Creates a socket for the given user which connects to the given @@ -60,14 +102,14 @@ public interface GuacamoleSocketService { * connection. * * @return - * A new GuacamoleSocket which is configured and connected to the given + * A new GuacamoleTunnel which is configured and connected to the given * connection. * * @throws GuacamoleException * If the connection cannot be established due to concurrent usage * rules. */ - GuacamoleSocket getGuacamoleSocket(AuthenticatedUser user, + GuacamoleTunnel getGuacamoleTunnel(AuthenticatedUser user, ModeledConnection connection, GuacamoleClientInformation info) throws GuacamoleException; @@ -81,7 +123,7 @@ public interface GuacamoleSocketService { * The connection to check. * * @return - * A connection containing connection records representing all + * A collection containing connection records representing all * currently-active connections. */ public Collection getActiveConnections(Connection connection); @@ -104,14 +146,14 @@ public interface GuacamoleSocketService { * connection group. * * @return - * A new GuacamoleSocket which is configured and connected to the given + * A new GuacamoleTunnel which is configured and connected to the given * connection group. * * @throws GuacamoleException * If the connection cannot be established due to concurrent usage * rules, or if the connection group is not balancing. */ - GuacamoleSocket getGuacamoleSocket(AuthenticatedUser user, + GuacamoleTunnel getGuacamoleTunnel(AuthenticatedUser user, ModeledConnectionGroup connectionGroup, GuacamoleClientInformation info) throws GuacamoleException; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ManagedInetGuacamoleSocket.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ManagedInetGuacamoleSocket.java similarity index 98% rename from extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ManagedInetGuacamoleSocket.java rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ManagedInetGuacamoleSocket.java index 8658bba4c..739b4776e 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ManagedInetGuacamoleSocket.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ManagedInetGuacamoleSocket.java @@ -20,7 +20,7 @@ * THE SOFTWARE. */ -package org.glyptodon.guacamole.auth.jdbc.socket; +package org.glyptodon.guacamole.auth.jdbc.tunnel; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.net.InetGuacamoleSocket; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/MultiseatGuacamoleSocketService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/MultiseatGuacamoleTunnelService.java similarity index 95% rename from extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/MultiseatGuacamoleSocketService.java rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/MultiseatGuacamoleTunnelService.java index 867c1b5d0..412e2f32e 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/MultiseatGuacamoleSocketService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/MultiseatGuacamoleTunnelService.java @@ -20,7 +20,7 @@ * THE SOFTWARE. */ -package org.glyptodon.guacamole.auth.jdbc.socket; +package org.glyptodon.guacamole.auth.jdbc.tunnel; import com.google.inject.Singleton; import java.util.Arrays; @@ -38,15 +38,15 @@ import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; /** - * GuacamoleSocketService implementation which restricts concurrency only on a + * GuacamoleTunnelService implementation which restricts concurrency only on a * per-user basis. Each connection or group may be used concurrently any number * of times, but each concurrent use must be associated with a different user. * * @author Michael Jumper */ @Singleton -public class MultiseatGuacamoleSocketService - extends AbstractGuacamoleSocketService { +public class MultiseatGuacamoleTunnelService + extends AbstractGuacamoleTunnelService { /** * The set of all active user/connection pairs. diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/Seat.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/Seat.java similarity index 98% rename from extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/Seat.java rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/Seat.java index 275536f98..008915f00 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/Seat.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/Seat.java @@ -20,7 +20,7 @@ * THE SOFTWARE. */ -package org.glyptodon.guacamole.auth.jdbc.socket; +package org.glyptodon.guacamole.auth.jdbc.tunnel; /** * A unique pairing of user and connection or connection group. diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/SingleSeatGuacamoleSocketService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/SingleSeatGuacamoleTunnelService.java similarity index 94% rename from extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/SingleSeatGuacamoleSocketService.java rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/SingleSeatGuacamoleTunnelService.java index 383e85f66..9fce08e5f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/SingleSeatGuacamoleSocketService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/SingleSeatGuacamoleTunnelService.java @@ -20,7 +20,7 @@ * THE SOFTWARE. */ -package org.glyptodon.guacamole.auth.jdbc.socket; +package org.glyptodon.guacamole.auth.jdbc.tunnel; import com.google.inject.Singleton; import java.util.Collections; @@ -36,7 +36,7 @@ import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; /** - * GuacamoleSocketService implementation which allows exactly one use + * GuacamoleTunnelService implementation which allows exactly one use * of any connection at any time. Concurrent usage of connections is not * allowed, and concurrent usage of connection groups is allowed only between * different users. @@ -44,8 +44,8 @@ import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; * @author Michael Jumper */ @Singleton -public class SingleSeatGuacamoleSocketService - extends AbstractGuacamoleSocketService { +public class SingleSeatGuacamoleTunnelService + extends AbstractGuacamoleTunnelService { /** * The set of all active connection identifiers. diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/UnrestrictedGuacamoleSocketService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/UnrestrictedGuacamoleTunnelService.java similarity index 92% rename from extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/UnrestrictedGuacamoleSocketService.java rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/UnrestrictedGuacamoleTunnelService.java index e5932d8c2..5aad81481 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/UnrestrictedGuacamoleSocketService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/UnrestrictedGuacamoleTunnelService.java @@ -20,7 +20,7 @@ * THE SOFTWARE. */ -package org.glyptodon.guacamole.auth.jdbc.socket; +package org.glyptodon.guacamole.auth.jdbc.tunnel; import com.google.inject.Singleton; import java.util.List; @@ -31,14 +31,14 @@ import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; /** - * GuacamoleSocketService implementation which imposes no restrictions + * GuacamoleTunnelService implementation which imposes no restrictions * whatsoever on the number of concurrent or duplicate connections. * * @author Michael Jumper */ @Singleton -public class UnrestrictedGuacamoleSocketService - extends AbstractGuacamoleSocketService { +public class UnrestrictedGuacamoleTunnelService + extends AbstractGuacamoleTunnelService { @Override protected ModeledConnection acquire(AuthenticatedUser user, diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/package-info.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/package-info.java similarity index 88% rename from extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/package-info.java rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/package-info.java index 42c8cc335..61657ffa5 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/package-info.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/package-info.java @@ -21,7 +21,7 @@ */ /** - * Classes related to obtaining/configuring Guacamole sockets, and restricting - * access to those sockets. + * Classes related to obtaining/configuring Guacamole tunnels, and restricting + * access to those tunnels. */ -package org.glyptodon.guacamole.auth.jdbc.socket; +package org.glyptodon.guacamole.auth.jdbc.tunnel; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/AuthenticatedUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/AuthenticatedUser.java index 7b01d4598..f778bbb44 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/AuthenticatedUser.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/AuthenticatedUser.java @@ -22,6 +22,7 @@ package org.glyptodon.guacamole.auth.jdbc.user; +import javax.servlet.http.HttpServletRequest; import org.glyptodon.guacamole.net.auth.Credentials; /** @@ -41,6 +42,27 @@ public class AuthenticatedUser { */ private final Credentials credentials; + /** + * The host from which this user authenticated. + */ + private final String remoteHost; + + /** + * Derives the remote host of the authenticating user from the given + * credentials object. + * + * @param credentials + * The credentials to derive the remote host from. + * + * @return + * The remote host from which the user with the given credentials is + * authenticating. + */ + private static String getRemoteHost(Credentials credentials) { + HttpServletRequest request = credentials.getRequest(); + return request.getRemoteAddr(); + } + /** * Creates a new AuthenticatedUser associating the given user with their * corresponding credentials. @@ -54,6 +76,7 @@ public class AuthenticatedUser { public AuthenticatedUser(ModeledUser user, Credentials credentials) { this.user = user; this.credentials = credentials; + this.remoteHost = getRemoteHost(credentials); } /** @@ -76,4 +99,14 @@ public class AuthenticatedUser { return credentials; } + /** + * Returns the host from which this user authenticated. + * + * @return + * The host from which this user authenticated. + */ + public String getRemoteHost() { + return remoteHost; + } + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserContext.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserContext.java index fac5b9af9..b28a0c49e 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserContext.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserContext.java @@ -28,10 +28,13 @@ import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ConnectionGroupDirector import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionDirectory; import com.google.inject.Inject; import com.google.inject.Provider; +import java.util.Collection; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.auth.jdbc.base.RestrictedObject; +import org.glyptodon.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService; import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionGroup; +import org.glyptodon.guacamole.net.auth.ConnectionRecord; import org.glyptodon.guacamole.net.auth.Directory; import org.glyptodon.guacamole.net.auth.User; @@ -45,6 +48,12 @@ import org.glyptodon.guacamole.net.auth.User; public class UserContext extends RestrictedObject implements org.glyptodon.guacamole.net.auth.UserContext { + /** + * Service for creating and tracking tunnels. + */ + @Inject + private GuacamoleTunnelService tunnelService; + /** * User directory restricted by the permissions of the user associated * with this context. @@ -114,4 +123,16 @@ public class UserContext extends RestrictedObject } + @Override + public Collection getActiveConnections() + throws GuacamoleException { + return tunnelService.getActiveConnections(getCurrentUser()); + } + + @Override + public ConnectionRecord getActiveConnection(String tunnelUUID) + throws GuacamoleException { + return tunnelService.getActiveConnection(getCurrentUser(), tunnelUUID); + } + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java index 3e7463b69..664ad7e67 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java @@ -29,11 +29,11 @@ import org.glyptodon.guacamole.net.auth.AuthenticationProvider; import org.glyptodon.guacamole.net.auth.Credentials; import org.glyptodon.guacamole.net.auth.UserContext; import org.glyptodon.guacamole.auth.jdbc.JDBCAuthenticationProviderModule; -import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService; -import org.glyptodon.guacamole.auth.jdbc.socket.MultiseatGuacamoleSocketService; -import org.glyptodon.guacamole.auth.jdbc.socket.BalancedGuacamoleSocketService; -import org.glyptodon.guacamole.auth.jdbc.socket.SingleSeatGuacamoleSocketService; -import org.glyptodon.guacamole.auth.jdbc.socket.UnrestrictedGuacamoleSocketService; +import org.glyptodon.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService; +import org.glyptodon.guacamole.auth.jdbc.tunnel.MultiseatGuacamoleTunnelService; +import org.glyptodon.guacamole.auth.jdbc.tunnel.BalancedGuacamoleTunnelService; +import org.glyptodon.guacamole.auth.jdbc.tunnel.SingleSeatGuacamoleTunnelService; +import org.glyptodon.guacamole.auth.jdbc.tunnel.UnrestrictedGuacamoleTunnelService; import org.glyptodon.guacamole.auth.jdbc.user.UserContextService; import org.glyptodon.guacamole.environment.Environment; import org.glyptodon.guacamole.environment.LocalEnvironment; @@ -69,7 +69,7 @@ public class MySQLAuthenticationProvider implements AuthenticationProvider { * @throws GuacamoleException * If an error occurs while reading the configuration options. */ - private Class + private Class getSocketServiceClass(Environment environment) throws GuacamoleException { @@ -81,11 +81,11 @@ public class MySQLAuthenticationProvider implements AuthenticationProvider { // Connections may not be used concurrently if (disallowDuplicate) - return SingleSeatGuacamoleSocketService.class; + return SingleSeatGuacamoleTunnelService.class; // Connections are reserved for a single user when in use else - return BalancedGuacamoleSocketService.class; + return BalancedGuacamoleTunnelService.class; } @@ -93,11 +93,11 @@ public class MySQLAuthenticationProvider implements AuthenticationProvider { // Connections may be used concurrently, but only once per user if (disallowDuplicate) - return MultiseatGuacamoleSocketService.class; + return MultiseatGuacamoleTunnelService.class; // Connection use is not restricted else - return UnrestrictedGuacamoleSocketService.class; + return UnrestrictedGuacamoleTunnelService.class; } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProvider.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProvider.java index 65bd2270a..1ee8afe2f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProvider.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProvider.java @@ -29,11 +29,11 @@ import org.glyptodon.guacamole.net.auth.AuthenticationProvider; import org.glyptodon.guacamole.net.auth.Credentials; import org.glyptodon.guacamole.net.auth.UserContext; import org.glyptodon.guacamole.auth.jdbc.JDBCAuthenticationProviderModule; -import org.glyptodon.guacamole.auth.jdbc.socket.BalancedGuacamoleSocketService; -import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService; -import org.glyptodon.guacamole.auth.jdbc.socket.MultiseatGuacamoleSocketService; -import org.glyptodon.guacamole.auth.jdbc.socket.SingleSeatGuacamoleSocketService; -import org.glyptodon.guacamole.auth.jdbc.socket.UnrestrictedGuacamoleSocketService; +import org.glyptodon.guacamole.auth.jdbc.tunnel.BalancedGuacamoleTunnelService; +import org.glyptodon.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService; +import org.glyptodon.guacamole.auth.jdbc.tunnel.MultiseatGuacamoleTunnelService; +import org.glyptodon.guacamole.auth.jdbc.tunnel.SingleSeatGuacamoleTunnelService; +import org.glyptodon.guacamole.auth.jdbc.tunnel.UnrestrictedGuacamoleTunnelService; import org.glyptodon.guacamole.auth.jdbc.user.UserContextService; import org.glyptodon.guacamole.environment.Environment; import org.glyptodon.guacamole.environment.LocalEnvironment; @@ -68,7 +68,7 @@ public class PostgreSQLAuthenticationProvider implements AuthenticationProvider * @throws GuacamoleException * If an error occurs while reading the configuration options. */ - private Class + private Class getSocketServiceClass(Environment environment) throws GuacamoleException { @@ -80,11 +80,11 @@ public class PostgreSQLAuthenticationProvider implements AuthenticationProvider // Connections may not be used concurrently if (disallowDuplicate) - return SingleSeatGuacamoleSocketService.class; + return SingleSeatGuacamoleTunnelService.class; // Connections are reserved for a single user when in use else - return BalancedGuacamoleSocketService.class; + return BalancedGuacamoleTunnelService.class; } @@ -92,11 +92,11 @@ public class PostgreSQLAuthenticationProvider implements AuthenticationProvider // Connections may be used concurrently, but only once per user if (disallowDuplicate) - return MultiseatGuacamoleSocketService.class; + return MultiseatGuacamoleTunnelService.class; // Connection use is not restricted else - return UnrestrictedGuacamoleSocketService.class; + return UnrestrictedGuacamoleTunnelService.class; } diff --git a/guacamole-common/src/main/java/org/glyptodon/guacamole/net/AbstractGuacamoleTunnel.java b/guacamole-common/src/main/java/org/glyptodon/guacamole/net/AbstractGuacamoleTunnel.java new file mode 100644 index 000000000..d8da19477 --- /dev/null +++ b/guacamole-common/src/main/java/org/glyptodon/guacamole/net/AbstractGuacamoleTunnel.java @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.net; + + +import java.util.concurrent.locks.ReentrantLock; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.io.GuacamoleReader; +import org.glyptodon.guacamole.io.GuacamoleWriter; + +/** + * Base GuacamoleTunnel implementation which synchronizes access to the + * underlying reader and writer with reentrant locks. Implementations need only + * provide the tunnel's UUID and socket. + * + * @author Michael Jumper + */ +public abstract class AbstractGuacamoleTunnel implements GuacamoleTunnel { + + /** + * Lock acquired when a read operation is in progress. + */ + private final ReentrantLock readerLock; + + /** + * Lock acquired when a write operation is in progress. + */ + private final ReentrantLock writerLock; + + /** + * Creates a new GuacamoleTunnel which synchronizes access to the + * Guacamole instruction stream associated with the underlying + * GuacamoleSocket. + */ + public AbstractGuacamoleTunnel() { + readerLock = new ReentrantLock(); + writerLock = new ReentrantLock(); + } + + /** + * Acquires exclusive read access to the Guacamole instruction stream + * and returns a GuacamoleReader for reading from that stream. + * + * @return A GuacamoleReader for reading from the Guacamole instruction + * stream. + */ + @Override + public GuacamoleReader acquireReader() { + readerLock.lock(); + return getSocket().getReader(); + } + + /** + * Relinquishes exclusive read access to the Guacamole instruction + * stream. This function should be called whenever a thread finishes using + * a GuacamoleTunnel's GuacamoleReader. + */ + @Override + public void releaseReader() { + readerLock.unlock(); + } + + /** + * Returns whether there are threads waiting for read access to the + * Guacamole instruction stream. + * + * @return true if threads are waiting for read access the Guacamole + * instruction stream, false otherwise. + */ + @Override + public boolean hasQueuedReaderThreads() { + return readerLock.hasQueuedThreads(); + } + + /** + * Acquires exclusive write access to the Guacamole instruction stream + * and returns a GuacamoleWriter for writing to that stream. + * + * @return A GuacamoleWriter for writing to the Guacamole instruction + * stream. + */ + @Override + public GuacamoleWriter acquireWriter() { + writerLock.lock(); + return getSocket().getWriter(); + } + + /** + * Relinquishes exclusive write access to the Guacamole instruction + * stream. This function should be called whenever a thread finishes using + * a GuacamoleTunnel's GuacamoleWriter. + */ + @Override + public void releaseWriter() { + writerLock.unlock(); + } + + @Override + public boolean hasQueuedWriterThreads() { + return writerLock.hasQueuedThreads(); + } + + @Override + public void close() throws GuacamoleException { + getSocket().close(); + } + + @Override + public boolean isOpen() { + return getSocket().isOpen(); + } + +} diff --git a/guacamole-common/src/main/java/org/glyptodon/guacamole/net/DelegatingGuacamoleTunnel.java b/guacamole-common/src/main/java/org/glyptodon/guacamole/net/DelegatingGuacamoleTunnel.java new file mode 100644 index 000000000..aa562989b --- /dev/null +++ b/guacamole-common/src/main/java/org/glyptodon/guacamole/net/DelegatingGuacamoleTunnel.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.net; + +import java.util.UUID; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.io.GuacamoleReader; +import org.glyptodon.guacamole.io.GuacamoleWriter; + +/** + * GuacamoleTunnel implementation which simply delegates all function calls to + * an underlying GuacamoleTunnel. + * + * @author Michael Jumper + */ +public class DelegatingGuacamoleTunnel implements GuacamoleTunnel { + + /** + * The wrapped GuacamoleTunnel. + */ + private final GuacamoleTunnel tunnel; + + /** + * Wraps the given tunnel such that all function calls against this tunnel + * will be delegated to it. + * + * @param tunnel + * The GuacamoleTunnel to wrap. + */ + public DelegatingGuacamoleTunnel(GuacamoleTunnel tunnel) { + this.tunnel = tunnel; + } + + @Override + public GuacamoleReader acquireReader() { + return tunnel.acquireReader(); + } + + @Override + public void releaseReader() { + tunnel.releaseReader(); + } + + @Override + public boolean hasQueuedReaderThreads() { + return tunnel.hasQueuedReaderThreads(); + } + + @Override + public GuacamoleWriter acquireWriter() { + return tunnel.acquireWriter(); + } + + @Override + public void releaseWriter() { + tunnel.releaseWriter(); + } + + @Override + public boolean hasQueuedWriterThreads() { + return tunnel.hasQueuedWriterThreads(); + } + + @Override + public UUID getUUID() { + return tunnel.getUUID(); + } + + @Override + public GuacamoleSocket getSocket() { + return tunnel.getSocket(); + } + + @Override + public void close() throws GuacamoleException { + tunnel.close(); + } + + @Override + public boolean isOpen() { + return tunnel.isOpen(); + } + +} diff --git a/guacamole-common/src/main/java/org/glyptodon/guacamole/net/GuacamoleTunnel.java b/guacamole-common/src/main/java/org/glyptodon/guacamole/net/GuacamoleTunnel.java index 65a847b18..c4e30b0f8 100644 --- a/guacamole-common/src/main/java/org/glyptodon/guacamole/net/GuacamoleTunnel.java +++ b/guacamole-common/src/main/java/org/glyptodon/guacamole/net/GuacamoleTunnel.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013 Glyptodon LLC + * Copyright (C) 2015 Glyptodon LLC * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -24,7 +24,6 @@ package org.glyptodon.guacamole.net; import java.util.UUID; -import java.util.concurrent.locks.ReentrantLock; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.io.GuacamoleReader; import org.glyptodon.guacamole.io.GuacamoleWriter; @@ -35,46 +34,7 @@ import org.glyptodon.guacamole.io.GuacamoleWriter; * * @author Michael Jumper */ -public class GuacamoleTunnel { - - /** - * The UUID associated with this tunnel. Every tunnel must have a - * corresponding UUID such that tunnel read/write requests can be - * directed to the proper tunnel. - */ - private UUID uuid; - - /** - * The GuacamoleSocket that tunnel should use for communication on - * behalf of the connecting user. - */ - private GuacamoleSocket socket; - - /** - * Lock acquired when a read operation is in progress. - */ - private ReentrantLock readerLock; - - /** - * Lock acquired when a write operation is in progress. - */ - private ReentrantLock writerLock; - - /** - * Creates a new GuacamoleTunnel which synchronizes access to the - * Guacamole instruction stream associated with the given GuacamoleSocket. - * - * @param socket The GuacamoleSocket to provide synchronized access for. - */ - public GuacamoleTunnel(GuacamoleSocket socket) { - - this.socket = socket; - uuid = UUID.randomUUID(); - - readerLock = new ReentrantLock(); - writerLock = new ReentrantLock(); - - } +public interface GuacamoleTunnel { /** * Acquires exclusive read access to the Guacamole instruction stream @@ -83,19 +43,14 @@ public class GuacamoleTunnel { * @return A GuacamoleReader for reading from the Guacamole instruction * stream. */ - public GuacamoleReader acquireReader() { - readerLock.lock(); - return socket.getReader(); - } + GuacamoleReader acquireReader(); /** * Relinquishes exclusive read access to the Guacamole instruction * stream. This function should be called whenever a thread finishes using * a GuacamoleTunnel's GuacamoleReader. */ - public void releaseReader() { - readerLock.unlock(); - } + void releaseReader(); /** * Returns whether there are threads waiting for read access to the @@ -104,9 +59,7 @@ public class GuacamoleTunnel { * @return true if threads are waiting for read access the Guacamole * instruction stream, false otherwise. */ - public boolean hasQueuedReaderThreads() { - return readerLock.hasQueuedThreads(); - } + boolean hasQueuedReaderThreads(); /** * Acquires exclusive write access to the Guacamole instruction stream @@ -115,19 +68,14 @@ public class GuacamoleTunnel { * @return A GuacamoleWriter for writing to the Guacamole instruction * stream. */ - public GuacamoleWriter acquireWriter() { - writerLock.lock(); - return socket.getWriter(); - } + GuacamoleWriter acquireWriter(); /** * Relinquishes exclusive write access to the Guacamole instruction * stream. This function should be called whenever a thread finishes using * a GuacamoleTunnel's GuacamoleWriter. */ - public void releaseWriter() { - writerLock.unlock(); - } + void releaseWriter(); /** * Returns whether there are threads waiting for write access to the @@ -136,18 +84,14 @@ public class GuacamoleTunnel { * @return true if threads are waiting for write access the Guacamole * instruction stream, false otherwise. */ - public boolean hasQueuedWriterThreads() { - return writerLock.hasQueuedThreads(); - } + boolean hasQueuedWriterThreads(); /** * Returns the unique identifier associated with this GuacamoleTunnel. * * @return The unique identifier associated with this GuacamoleTunnel. */ - public UUID getUUID() { - return uuid; - } + UUID getUUID(); /** * Returns the GuacamoleSocket used by this GuacamoleTunnel for reading @@ -155,9 +99,7 @@ public class GuacamoleTunnel { * * @return The GuacamoleSocket used by this GuacamoleTunnel. */ - public GuacamoleSocket getSocket() { - return socket; - } + GuacamoleSocket getSocket(); /** * Release all resources allocated to this GuacamoleTunnel. @@ -165,17 +107,13 @@ public class GuacamoleTunnel { * @throws GuacamoleException if an error occurs while releasing * resources. */ - public void close() throws GuacamoleException { - socket.close(); - } + void close() throws GuacamoleException; /** * Returns whether this GuacamoleTunnel is open, or has been closed. * * @return true if this GuacamoleTunnel is open, false if it is closed. */ - public boolean isOpen() { - return socket.isOpen(); - } + boolean isOpen(); } diff --git a/guacamole-common/src/main/java/org/glyptodon/guacamole/net/SimpleGuacamoleTunnel.java b/guacamole-common/src/main/java/org/glyptodon/guacamole/net/SimpleGuacamoleTunnel.java new file mode 100644 index 000000000..f0c28cb4e --- /dev/null +++ b/guacamole-common/src/main/java/org/glyptodon/guacamole/net/SimpleGuacamoleTunnel.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.net; + + +import java.util.UUID; + +/** + * GuacamoleTunnel implementation which uses a provided socket. The UUID of + * the tunnel will be randomly generated. + * + * @author Michael Jumper + */ +public class SimpleGuacamoleTunnel extends AbstractGuacamoleTunnel { + + /** + * The UUID associated with this tunnel. Every tunnel must have a + * corresponding UUID such that tunnel read/write requests can be + * directed to the proper tunnel. + */ + private final UUID uuid = UUID.randomUUID(); + + /** + * The GuacamoleSocket that tunnel should use for communication on + * behalf of the connecting user. + */ + private final GuacamoleSocket socket; + + /** + * Creates a new GuacamoleTunnel which synchronizes access to the + * Guacamole instruction stream associated with the given GuacamoleSocket. + * + * @param socket The GuacamoleSocket to provide synchronized access for. + */ + public SimpleGuacamoleTunnel(GuacamoleSocket socket) { + this.socket = socket; + } + + @Override + public UUID getUUID() { + return uuid; + } + + @Override + public GuacamoleSocket getSocket() { + return socket; + } + +} diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connectable.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connectable.java index 61d2ebfd9..d81a679af 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connectable.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connectable.java @@ -23,7 +23,7 @@ package org.glyptodon.guacamole.net.auth; import org.glyptodon.guacamole.GuacamoleException; -import org.glyptodon.guacamole.net.GuacamoleSocket; +import org.glyptodon.guacamole.net.GuacamoleTunnel; import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; /** @@ -42,13 +42,13 @@ public interface Connectable { * Information associated with the connecting client. * * @return - * A fully-established GuacamoleSocket. + * A fully-established GuacamoleTunnel. * * @throws GuacamoleException * If an error occurs while connecting to guacd, or if permission to * connect is denied. */ - public GuacamoleSocket connect(GuacamoleClientInformation info) + public GuacamoleTunnel connect(GuacamoleClientInformation info) throws GuacamoleException; /** diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionRecord.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionRecord.java index 208b3c397..a4e2fcbe5 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionRecord.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionRecord.java @@ -23,6 +23,7 @@ package org.glyptodon.guacamole.net.auth; import java.util.Date; +import org.glyptodon.guacamole.net.GuacamoleTunnel; /** * A logging record describing when a user started and ended usage of a @@ -32,6 +33,16 @@ import java.util.Date; */ public interface ConnectionRecord { + /** + * Returns the identifier of the connection associated with this connection + * record. + * + * @return + * The identifier of the connection associated with this connection + * record. + */ + public String getIdentifier(); + /** * Returns the date and time the connection began. * @@ -47,6 +58,17 @@ public interface ConnectionRecord { */ public Date getEndDate(); + /** + * Returns the hostname or IP address of the remote host that used the + * connection associated with this record, if known. If the hostname or IP + * address is not known, null is returned. + * + * @return + * The hostname or IP address of the remote host, or null if this + * information is not available. + */ + public String getRemoteHost(); + /** * Returns the name of the user who used or is using the connection at the * times given by this connection record. @@ -65,4 +87,15 @@ public interface ConnectionRecord { */ public boolean isActive(); + /** + * Returns the connected GuacamoleTunnel of the connection associated with + * this record, if any. If the connection is not active, or access to + * the socket is denied, null is returned. + * + * @return + * The connected GuacamoleTunnel, if any, or null if the connection is + * not active or permission is denied. + */ + public GuacamoleTunnel getTunnel(); + } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/UserContext.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/UserContext.java index c38d9a90f..7c52834de 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/UserContext.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/UserContext.java @@ -22,6 +22,7 @@ package org.glyptodon.guacamole.net.auth; +import java.util.Collection; import org.glyptodon.guacamole.GuacamoleException; /** @@ -95,4 +96,41 @@ public interface UserContext { */ ConnectionGroup getRootConnectionGroup() throws GuacamoleException; + /** + * Returns a collection of connection records associated with all active + * connections to which the current user has access. For an administrative + * user, this may include connections associated with other users. + * + * @return + * A collection of all connection records associated with active + * connections to which the current user has access. + * + * @throws GuacamoleException + * If an error occurs while reading active connection records, or if + * permission is denied. + */ + Collection getActiveConnections() + throws GuacamoleException; + + /** + * Returns the connection record associated with the active connection + * having the tunnel with the given UUID. The active connection will only + * be returned if the current user has access. + * + * @param tunnelUUID + * The UUID of the tunnel whose associated connection record should be + * returned. + * + * @return + * The connection record associated with the active connection having + * the tunnel with the given UUID, if any, or null if no such + * connection exists. + * + * @throws GuacamoleException + * If an error occurs while reading active connection records, or if + * permission is denied. + */ + ConnectionRecord getActiveConnection(String tunnelUUID) + throws GuacamoleException; + } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnection.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnection.java index fe5070097..a1ae0e3f0 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnection.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnection.java @@ -28,8 +28,10 @@ import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.environment.Environment; import org.glyptodon.guacamole.environment.LocalEnvironment; import org.glyptodon.guacamole.net.GuacamoleSocket; +import org.glyptodon.guacamole.net.GuacamoleTunnel; import org.glyptodon.guacamole.net.InetGuacamoleSocket; import org.glyptodon.guacamole.net.SSLGuacamoleSocket; +import org.glyptodon.guacamole.net.SimpleGuacamoleTunnel; import org.glyptodon.guacamole.net.auth.AbstractConnection; import org.glyptodon.guacamole.net.auth.ConnectionRecord; import org.glyptodon.guacamole.protocol.ConfiguredGuacamoleSocket; @@ -84,7 +86,7 @@ public class SimpleConnection extends AbstractConnection { } @Override - public GuacamoleSocket connect(GuacamoleClientInformation info) + public GuacamoleTunnel connect(GuacamoleClientInformation info) throws GuacamoleException { Environment env = new LocalEnvironment(); @@ -93,19 +95,24 @@ public class SimpleConnection extends AbstractConnection { String hostname = env.getProperty(Environment.GUACD_HOSTNAME); int port = env.getProperty(Environment.GUACD_PORT); + GuacamoleSocket socket; + // If guacd requires SSL, use it if (env.getProperty(Environment.GUACD_SSL, false)) - return new ConfiguredGuacamoleSocket( + socket = new ConfiguredGuacamoleSocket( new SSLGuacamoleSocket(hostname, port), config, info ); - // Return connected socket - return new ConfiguredGuacamoleSocket( - new InetGuacamoleSocket(hostname, port), - config, info - ); + // Otherwise, just connect directly via TCP + else + socket = new ConfiguredGuacamoleSocket( + new InetGuacamoleSocket(hostname, port), + config, info + ); + return new SimpleGuacamoleTunnel(socket); + } @Override diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroup.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroup.java index 71e73433e..a302f4676 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroup.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroup.java @@ -27,7 +27,7 @@ import java.util.HashSet; import java.util.Set; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleSecurityException; -import org.glyptodon.guacamole.net.GuacamoleSocket; +import org.glyptodon.guacamole.net.GuacamoleTunnel; import org.glyptodon.guacamole.net.auth.AbstractConnectionGroup; import org.glyptodon.guacamole.net.auth.ConnectionGroup; import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; @@ -102,7 +102,7 @@ public class SimpleConnectionGroup extends AbstractConnectionGroup { } @Override - public GuacamoleSocket connect(GuacamoleClientInformation info) + public GuacamoleTunnel connect(GuacamoleClientInformation info) throws GuacamoleException { throw new GuacamoleSecurityException("Permission denied."); } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java index 8ee7e84c1..480c79017 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java @@ -30,6 +30,7 @@ import java.util.UUID; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionGroup; +import org.glyptodon.guacamole.net.auth.ConnectionRecord; import org.glyptodon.guacamole.net.auth.Directory; import org.glyptodon.guacamole.net.auth.User; import org.glyptodon.guacamole.net.auth.UserContext; @@ -167,4 +168,16 @@ public class SimpleUserContext implements UserContext { return rootGroup; } + @Override + public Collection getActiveConnections() + throws GuacamoleException { + return Collections.EMPTY_LIST; + } + + @Override + public ConnectionRecord getActiveConnection(String tunnelUUID) + throws GuacamoleException { + return null; + } + } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/TunnelRequestService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/TunnelRequestService.java index b0ba6ee39..2e4033893 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/TunnelRequestService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/TunnelRequestService.java @@ -31,7 +31,7 @@ import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleSecurityException; import org.glyptodon.guacamole.GuacamoleUnauthorizedException; import org.glyptodon.guacamole.io.GuacamoleReader; -import org.glyptodon.guacamole.net.GuacamoleSocket; +import org.glyptodon.guacamole.net.DelegatingGuacamoleTunnel; import org.glyptodon.guacamole.net.GuacamoleTunnel; import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionGroup; @@ -204,7 +204,7 @@ public class TunnelRequestService { info.getVideoMimetypes().addAll(video_mimetypes); // Create connected socket from identifier - GuacamoleSocket socket; + GuacamoleTunnel tunnel; switch (id_type) { // Connection identifiers @@ -221,8 +221,8 @@ public class TunnelRequestService { throw new GuacamoleSecurityException("Requested connection is not authorized."); } - // Connect socket - socket = connection.connect(info); + // Connect tunnel + tunnel = connection.connect(info); logger.info("User \"{}\" successfully connected to \"{}\".", context.self().getIdentifier(), id); break; } @@ -241,8 +241,8 @@ public class TunnelRequestService { throw new GuacamoleSecurityException("Requested connection group is not authorized."); } - // Connect socket - socket = group.connect(info); + // Connect tunnel + tunnel = group.connect(info); logger.info("User \"{}\" successfully connected to group \"{}\".", context.self().getIdentifier(), id); break; } @@ -253,8 +253,8 @@ public class TunnelRequestService { } - // Associate socket with tunnel - GuacamoleTunnel tunnel = new GuacamoleTunnel(socket) { + // Track tunnel open/close + GuacamoleTunnel monitoredTunnel = new DelegatingGuacamoleTunnel(tunnel) { @Override public GuacamoleReader acquireReader() { @@ -308,13 +308,13 @@ public class TunnelRequestService { }; // Notify listeners about connection - if (!notifyConnect(session, tunnel)) { + if (!notifyConnect(session, monitoredTunnel)) { logger.info("Successful connection canceled by hook."); return null; } - session.addTunnel(tunnel); - return tunnel; + session.addTunnel(monitoredTunnel); + return monitoredTunnel; } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletModule.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletModule.java index cc4e90e6d..a2f0232f3 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletModule.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletModule.java @@ -31,6 +31,7 @@ import org.glyptodon.guacamole.net.basic.rest.clipboard.ClipboardRESTService; import org.glyptodon.guacamole.net.basic.rest.connection.ConnectionRESTService; import org.glyptodon.guacamole.net.basic.rest.connectiongroup.ConnectionGroupRESTService; import org.glyptodon.guacamole.net.basic.rest.protocol.ProtocolRESTService; +import org.glyptodon.guacamole.net.basic.rest.tunnel.TunnelRESTService; import org.glyptodon.guacamole.net.basic.rest.user.UserRESTService; /** @@ -50,6 +51,7 @@ public class RESTServletModule extends ServletModule { bind(ProtocolRESTService.class); bind(UserRESTService.class); bind(TokenRESTService.class); + bind(TunnelRESTService.class); // Set up the servlet and JSON mappings bind(GuiceContainer.class); diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnectionRecord.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnectionRecord.java index e1423ac8f..e3912ecbe 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnectionRecord.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnectionRecord.java @@ -43,6 +43,11 @@ public class APIConnectionRecord { */ private final Date endDate; + /** + * The host from which the connection originated, if known. + */ + private final String remoteHost; + /** * The name of the user who used or is using the connection. */ @@ -61,10 +66,11 @@ public class APIConnectionRecord { * The record to copy data from. */ public APIConnectionRecord(ConnectionRecord record) { - this.startDate = record.getStartDate(); - this.endDate = record.getEndDate(); - this.username = record.getUsername(); - this.active = record.isActive(); + this.startDate = record.getStartDate(); + this.endDate = record.getEndDate(); + this.remoteHost = record.getRemoteHost(); + this.username = record.getUsername(); + this.active = record.isActive(); } /** @@ -88,6 +94,16 @@ public class APIConnectionRecord { return endDate; } + /** + * Returns the remote host from which this connection originated. + * + * @return + * The remote host from which this connection originated. + */ + public String getRemoteHost() { + return remoteHost; + } + /** * Returns the name of the user who used or is using the connection at the * times given by this connection record. diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnectionWrapper.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnectionWrapper.java index 33fe5047f..bbfb6916c 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnectionWrapper.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnectionWrapper.java @@ -26,7 +26,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import org.glyptodon.guacamole.GuacamoleException; -import org.glyptodon.guacamole.net.GuacamoleSocket; +import org.glyptodon.guacamole.net.GuacamoleTunnel; import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionRecord; import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; @@ -116,7 +116,7 @@ public class APIConnectionWrapper implements Connection { } @Override - public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException { + public GuacamoleTunnel connect(GuacamoleClientInformation info) throws GuacamoleException { throw new UnsupportedOperationException("Operation not supported."); } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java index 9007e75dd..c37aee94a 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java @@ -24,7 +24,7 @@ package org.glyptodon.guacamole.net.basic.rest.connectiongroup; import java.util.Set; import org.glyptodon.guacamole.GuacamoleException; -import org.glyptodon.guacamole.net.GuacamoleSocket; +import org.glyptodon.guacamole.net.GuacamoleTunnel; import org.glyptodon.guacamole.net.auth.ConnectionGroup; import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; @@ -106,7 +106,7 @@ public class APIConnectionGroupWrapper implements ConnectionGroup { } @Override - public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException { + public GuacamoleTunnel connect(GuacamoleClientInformation info) throws GuacamoleException { throw new UnsupportedOperationException("Operation not supported."); } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/tunnel/APITunnel.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/tunnel/APITunnel.java new file mode 100644 index 000000000..ca1a0604c --- /dev/null +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/tunnel/APITunnel.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.net.basic.rest.tunnel; + +import java.util.Date; +import org.glyptodon.guacamole.net.auth.ConnectionRecord; + +/** + * Tunnel-related information which may be exposed through the REST endpoints. + * + * @author Michael Jumper + */ +public class APITunnel { + + /** + * The identifier of the connection associated with this tunnel. + */ + private final String identifier; + + /** + * The date and time the connection began. + */ + private final Date startDate; + + /** + * The host from which the connection originated, if known. + */ + private final String remoteHost; + + /** + * The name of the user who used or is using the connection. + */ + private final String username; + + /** + * The UUID of the tunnel. + */ + private final String uuid; + + /** + * Creates a new APITunnel, copying the information from the given + * connection record. + * + * @param record + * The record to copy data from. + * + * @param uuid + * The UUID of the associated GuacamoleTunnel. + */ + public APITunnel(ConnectionRecord record, String uuid) { + this.identifier = record.getIdentifier(); + this.startDate = record.getStartDate(); + this.remoteHost = record.getRemoteHost(); + this.username = record.getUsername(); + this.uuid = uuid; + } + + /** + * Returns the identifier of the connection associated with this tunnel. + * + * @return + * The identifier of the connection associated with this tunnel. + */ + public String getIdentifier() { + return identifier; + } + + /** + * Returns the date and time the connection began. + * + * @return + * The date and time the connection began. + */ + public Date getStartDate() { + return startDate; + } + + /** + * Returns the remote host from which this connection originated. + * + * @return + * The remote host from which this connection originated. + */ + public String getRemoteHost() { + return remoteHost; + } + + /** + * Returns the name of the user who used or is using the connection at the + * times given by this tunnel. + * + * @return + * The name of the user who used or is using the associated connection. + */ + public String getUsername() { + return username; + } + + /** + * Returns the UUID of the underlying Guacamole tunnel. Absolutely every + * Guacamole tunnel has an associated UUID. + * + * @return + * The UUID of the underlying Guacamole tunnel. + */ + public String getUUID() { + return uuid; + } + +} diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/tunnel/TunnelRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/tunnel/TunnelRESTService.java new file mode 100644 index 000000000..231f8586a --- /dev/null +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/tunnel/TunnelRESTService.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.net.basic.rest.tunnel; + +import com.google.inject.Inject; +import java.util.ArrayList; +import java.util.List; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.GuacamoleResourceNotFoundException; +import org.glyptodon.guacamole.GuacamoleUnsupportedException; +import org.glyptodon.guacamole.net.GuacamoleTunnel; +import org.glyptodon.guacamole.net.auth.ConnectionRecord; +import org.glyptodon.guacamole.net.auth.UserContext; +import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure; +import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A REST Service for retrieving and managing the tunnels of active connections. + * + * @author Michael Jumper + */ +@Path("/tunnels") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class TunnelRESTService { + + /** + * Logger for this class. + */ + private static final Logger logger = LoggerFactory.getLogger(TunnelRESTService.class); + + /** + * A service for authenticating users from auth tokens. + */ + @Inject + private AuthenticationService authenticationService; + + /** + * Retrieves the tunnels of all active connections visible to the current + * user. + * + * @param authToken + * The authentication token that is used to authenticate the user + * performing the operation. + * + * @return + * The tunnels of all active connections visible to the current user. + * + * @throws GuacamoleException + * If an error occurs while retrieving the tunnels. + */ + @GET + @Path("/") + @AuthProviderRESTExposure + public List getTunnels(@QueryParam("token") String authToken) + throws GuacamoleException { + + UserContext userContext = authenticationService.getUserContext(authToken); + + // Retrieve all active tunnels + List apiTunnels = new ArrayList(); + for (ConnectionRecord record : userContext.getActiveConnections()) { + + // Locate associated tunnel and UUID + GuacamoleTunnel tunnel = record.getTunnel(); + if (tunnel != null) + apiTunnels.add(new APITunnel(record, tunnel.getUUID().toString())); + + } + + return apiTunnels; + + } + + /** + * Deletes the tunnel having the given UUID, effectively closing the + * tunnel and killing the associated connection. + * + * @param authToken + * The authentication token that is used to authenticate the user + * performing the operation. + * + * @param tunnelUUID + * The UUID associated with the tunnel being deleted. + * + * @throws GuacamoleException + * If an error occurs while deleting the tunnel. + */ + @DELETE + @Path("/{tunnelUUID}") + @AuthProviderRESTExposure + public void deleteTunnel(@QueryParam("token") String authToken, + @PathParam("tunnelUUID") String tunnelUUID) + throws GuacamoleException { + + UserContext userContext = authenticationService.getUserContext(authToken); + + // Retrieve specified tunnel + ConnectionRecord record = userContext.getActiveConnection(tunnelUUID); + if (record == null) + throw new GuacamoleResourceNotFoundException("No such tunnel: \"" + tunnelUUID + "\""); + + // Close tunnel, if not already closed + GuacamoleTunnel tunnel = record.getTunnel(); + if (tunnel != null && tunnel.isOpen()) + tunnel.close(); + + } + +} diff --git a/guacamole/src/main/webapp/app/rest/services/tunnelService.js b/guacamole/src/main/webapp/app/rest/services/tunnelService.js new file mode 100644 index 000000000..ca9c5a838 --- /dev/null +++ b/guacamole/src/main/webapp/app/rest/services/tunnelService.js @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2014 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/** + * Service for operating on tunnels via the REST API. + */ +angular.module('rest').factory('tunnelService', ['$http', 'authenticationService', + function tunnelService($http, authenticationService) { + + var service = {}; + + /** + * Makes a request to the REST API to get the list of active tunnels, + * returning a promise that provides an array of @link{ActiveTunnel} + * objects if successful. + * + * @returns {Promise.} + * A promise which will resolve with an array of @link{ActiveTunnel} + * objects upon success. + */ + service.getActiveTunnels = function getActiveTunnels() { + + // Build HTTP parameters set + var httpParameters = { + token : authenticationService.getCurrentToken() + }; + + // Retrieve tunnels + return $http({ + method : 'GET', + url : 'api/tunnels', + params : httpParameters + }); + + }; + + /** + * Makes a request to the REST API to delete the tunnel having the given + * UUID, effectively disconnecting the tunnel, returning a promise that can + * be used for processing the results of the call. + * + * @param {String} uuid + * The UUID of the tunnel to delete. + * + * @returns {Promise} + * A promise for the HTTP call which will succeed if and only if the + * delete operation is successful. + */ + service.deleteActiveTunnel = function deleteActiveTunnel(uuid) { + + // Build HTTP parameters set + var httpParameters = { + token : authenticationService.getCurrentToken() + }; + + // Delete connection + return $http({ + method : 'DELETE', + url : 'api/tunnels/' + encodeURIComponent(uuid), + params : httpParameters + }); + + }; + + return service; + +}]); diff --git a/guacamole/src/main/webapp/app/rest/types/ActiveTunnel.js b/guacamole/src/main/webapp/app/rest/types/ActiveTunnel.js new file mode 100644 index 000000000..996105a64 --- /dev/null +++ b/guacamole/src/main/webapp/app/rest/types/ActiveTunnel.js @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +/** + * Service which defines the ActiveTunnel class. + */ +angular.module('rest').factory('ActiveTunnel', [function defineActiveTunnel() { + + /** + * The object returned by REST API calls when representing the data + * associated with an active tunnel. Each tunnel denotes an active + * connection, uniquely identified by the tunnel UUID. + * + * @constructor + * @param {ActiveTunnel|Object} [template={}] + * The object whose properties should be copied within the new + * ActiveTunnel. + */ + var ActiveTunnel = function ActiveTunnel(template) { + + // Use empty object by default + template = template || {}; + + /** + * The identifier of the connection associated with this tunnel. + * + * @type String + */ + this.identifier = template.identifier; + + /** + * The time that the tunnel began, in seconds since + * 1970-01-01 00:00:00 UTC. + * + * @type Number + */ + this.startDate = template.startDate; + + /** + * The remote host that initiated the tunnel, if known. + * + * @type String + */ + this.remoteHost = template.remoteHost; + + /** + * The username of the user associated with the tunnel. + * + * @type String + */ + this.username = template.username; + + /** + * The UUID which uniquely identifies the tunnel. + * + * @type String + */ + this.uuid = template.uuid; + + }; + + return ActiveTunnel; + +}]); \ No newline at end of file diff --git a/guacamole/src/main/webapp/app/rest/types/ConnectionHistoryEntry.js b/guacamole/src/main/webapp/app/rest/types/ConnectionHistoryEntry.js index 9f0023323..299c65c13 100644 --- a/guacamole/src/main/webapp/app/rest/types/ConnectionHistoryEntry.js +++ b/guacamole/src/main/webapp/app/rest/types/ConnectionHistoryEntry.js @@ -60,6 +60,13 @@ angular.module('rest').factory('ConnectionHistoryEntry', [function defineConnect */ this.endDate = template.endDate; + /** + * The remote host that initiated this connection, if known. + * + * @type String + */ + this.remoteHost = template.remoteHost; + /** * The username of the user associated with this particular usage of * the connection.