From b33e5158950fe2ddac462497ed5d8963ae380ba5 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 17 Mar 2015 13:21:05 -0700 Subject: [PATCH] GUAC-1132: Associate tunnels with records, not sockets. Provide tunnel for connect(). --- .../jdbc/connection/ConnectionService.java | 8 +- .../jdbc/connection/ModeledConnection.java | 4 +- .../connection/ModeledConnectionRecord.java | 4 +- .../ConnectionGroupService.java | 8 +- .../ModeledConnectionGroup.java | 4 +- .../connectiongroup/RootConnectionGroup.java | 4 +- .../AbstractGuacamoleSocketService.java | 23 ++- .../jdbc/socket/ActiveConnectionRecord.java | 20 +- .../jdbc/socket/GuacamoleSocketService.java | 10 +- .../guacamole/auth/jdbc/user/UserContext.java | 10 +- .../net/DelegatingGuacamoleTunnel.java | 104 ++++++++++ .../guacamole/net/GuacamoleTunnel.java | 86 ++------- .../net/SynchronizedGuacamoleTunnel.java | 181 ++++++++++++++++++ .../guacamole/net/auth/Connectable.java | 6 +- .../guacamole/net/auth/ConnectionRecord.java | 8 +- .../guacamole/net/auth/UserContext.java | 21 ++ .../net/auth/simple/SimpleConnection.java | 21 +- .../auth/simple/SimpleConnectionGroup.java | 4 +- .../net/auth/simple/SimpleUserContext.java | 6 + .../net/basic/TunnelRequestService.java | 22 +-- .../rest/connection/APIConnectionWrapper.java | 4 +- .../APIConnectionGroupWrapper.java | 4 +- 22 files changed, 415 insertions(+), 147 deletions(-) create mode 100644 guacamole-common/src/main/java/org/glyptodon/guacamole/net/DelegatingGuacamoleTunnel.java create mode 100644 guacamole-common/src/main/java/org/glyptodon/guacamole/net/SynchronizedGuacamoleTunnel.java 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..e67afad31 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 @@ -40,7 +40,7 @@ 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; @@ -403,19 +403,19 @@ public class ConnectionService extends GroupedDirectoryObjectService } @Override - public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException { + public GuacamoleTunnel connect(GuacamoleClientInformation info) throws GuacamoleException { return connectionService.connect(getCurrentUser(), this, info); } 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 76e3fcc8a..f6701da2d 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,7 +24,7 @@ package org.glyptodon.guacamole.auth.jdbc.connection; import java.util.Date; -import org.glyptodon.guacamole.net.GuacamoleSocket; +import org.glyptodon.guacamole.net.GuacamoleTunnel; import org.glyptodon.guacamole.net.auth.ConnectionRecord; /** @@ -84,7 +84,7 @@ public class ModeledConnectionRecord implements ConnectionRecord { } @Override - public GuacamoleSocket getSocket() { + 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..77a03b012 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 @@ -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; @@ -235,19 +235,19 @@ public class ConnectionGroupService extends GroupedDirectoryObjectService getActiveConnections() throws GuacamoleException { + public Collection getActiveConnections() + throws GuacamoleException { return socketService.getActiveConnections(getCurrentUser()); } + @Override + public ConnectionRecord getActiveConnection(String tunnelUUID) + throws GuacamoleException { + // STUB + return null; + } + } 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..3c27f73ae 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(); - } + public 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(); - } + public 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(); - } + public 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(); - } + public boolean hasQueuedWriterThreads(); /** * Returns the unique identifier associated with this GuacamoleTunnel. * * @return The unique identifier associated with this GuacamoleTunnel. */ - public UUID getUUID() { - return uuid; - } + public 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; - } + public 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(); - } + public 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(); - } + public boolean isOpen(); } diff --git a/guacamole-common/src/main/java/org/glyptodon/guacamole/net/SynchronizedGuacamoleTunnel.java b/guacamole-common/src/main/java/org/glyptodon/guacamole/net/SynchronizedGuacamoleTunnel.java new file mode 100644 index 000000000..3e8dc77a1 --- /dev/null +++ b/guacamole-common/src/main/java/org/glyptodon/guacamole/net/SynchronizedGuacamoleTunnel.java @@ -0,0 +1,181 @@ +/* + * 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 java.util.concurrent.locks.ReentrantLock; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.io.GuacamoleReader; +import org.glyptodon.guacamole.io.GuacamoleWriter; + +/** + * GuacamoleTunnel implementation which synchronizes access to the underlying + * reader and write with reentrant locks. + * + * @author Michael Jumper + */ +public class SynchronizedGuacamoleTunnel implements 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 final UUID uuid; + + /** + * The GuacamoleSocket that tunnel should use for communication on + * behalf of the connecting user. + */ + private final GuacamoleSocket socket; + + /** + * 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 given GuacamoleSocket. + * + * @param socket The GuacamoleSocket to provide synchronized access for. + */ + public SynchronizedGuacamoleTunnel(GuacamoleSocket socket) { + + this.socket = socket; + uuid = UUID.randomUUID(); + + 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. + */ + public GuacamoleReader acquireReader() { + readerLock.lock(); + return socket.getReader(); + } + + /** + * 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(); + } + + /** + * 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. + */ + 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. + */ + public GuacamoleWriter acquireWriter() { + writerLock.lock(); + return socket.getWriter(); + } + + /** + * 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(); + } + + /** + * Returns whether there are threads waiting for write access to the + * Guacamole instruction stream. + * + * @return true if threads are waiting for write access the Guacamole + * instruction stream, false otherwise. + */ + public boolean hasQueuedWriterThreads() { + return writerLock.hasQueuedThreads(); + } + + /** + * Returns the unique identifier associated with this GuacamoleTunnel. + * + * @return The unique identifier associated with this GuacamoleTunnel. + */ + public UUID getUUID() { + return uuid; + } + + /** + * Returns the GuacamoleSocket used by this GuacamoleTunnel for reading + * and writing. + * + * @return The GuacamoleSocket used by this GuacamoleTunnel. + */ + public GuacamoleSocket getSocket() { + return socket; + } + + /** + * Release all resources allocated to this GuacamoleTunnel. + * + * @throws GuacamoleException if an error occurs while releasing + * resources. + */ + public void close() throws GuacamoleException { + socket.close(); + } + + /** + * 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(); + } + +} 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 5789424b2..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,7 +23,7 @@ package org.glyptodon.guacamole.net.auth; import java.util.Date; -import org.glyptodon.guacamole.net.GuacamoleSocket; +import org.glyptodon.guacamole.net.GuacamoleTunnel; /** * A logging record describing when a user started and ended usage of a @@ -88,14 +88,14 @@ public interface ConnectionRecord { public boolean isActive(); /** - * Returns the connected GuacamoleSocket of the connection associated with + * 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 GuacamoleSocket, if any, or null if the connection is + * The connected GuacamoleTunnel, if any, or null if the connection is * not active or permission is denied. */ - public GuacamoleSocket getSocket(); + 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 010e3e3a6..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 @@ -112,4 +112,25 @@ public interface UserContext { 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..9aeb0c81c 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.SynchronizedGuacamoleTunnel; 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 SynchronizedGuacamoleTunnel(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 3f19ec7fc..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 @@ -174,4 +174,10 @@ public class SimpleUserContext implements UserContext { 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/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."); }