diff --git a/guacamole-ext/src/main/resources/org/glyptodon/guacamole/protocols/rdp.xml b/guacamole-ext/src/main/resources/org/glyptodon/guacamole/protocols/rdp.xml
index 45bc6a2da..af39ae4f7 100644
--- a/guacamole-ext/src/main/resources/org/glyptodon/guacamole/protocols/rdp.xml
+++ b/guacamole-ext/src/main/resources/org/glyptodon/guacamole/protocols/rdp.xml
@@ -24,6 +24,7 @@
+
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 2e4033893..43ec2d395 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
@@ -29,7 +29,6 @@ import java.util.List;
import org.glyptodon.guacamole.GuacamoleClientException;
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.DelegatingGuacamoleTunnel;
import org.glyptodon.guacamole.net.GuacamoleTunnel;
@@ -55,6 +54,7 @@ import org.slf4j.LoggerFactory;
* that use purely the Guacamole API.
*
* @author Michael Jumper
+ * @author Vasily Loginov
*/
@Singleton
public class TunnelRequestService {
@@ -148,33 +148,18 @@ public class TunnelRequestService {
}
-
/**
- * Creates a new tunnel using the parameters and credentials present in
- * the given request.
- *
- * @param request The request describing the tunnel to create.
- * @return The created tunnel, or null if the tunnel could not be created.
- * @throws GuacamoleException If an error occurs while creating the tunnel.
+ * Reads and returns the client information provided within the given
+ * request.
+ *
+ * @param request
+ * The request describing tunnel to create.
+ *
+ * @return GuacamoleClientInformation
+ * An object containing information about the client sending the tunnel
+ * request.
*/
- public GuacamoleTunnel createTunnel(TunnelRequest request)
- throws GuacamoleException {
-
- // Get auth token and session
- final String authToken = request.getParameter("authToken");
- GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
-
- // Get ID of connection
- String id = request.getParameter("id");
- TunnelRequest.IdentifierType id_type = TunnelRequest.IdentifierType.getType(id);
-
- // Do not continue if unable to determine type
- if (id_type == null)
- throw new GuacamoleClientException("Illegal identifier - unknown type.");
-
- // Remove prefix
- id = id.substring(id_type.PREFIX.length());
-
+ protected GuacamoleClientInformation getClientInformation(TunnelRequest request) {
// Get client information
GuacamoleClientInformation info = new GuacamoleClientInformation();
@@ -203,7 +188,46 @@ public class TunnelRequestService {
if (video_mimetypes != null)
info.getVideoMimetypes().addAll(video_mimetypes);
- // Create connected socket from identifier
+ return info;
+ }
+
+ /**
+ * Creates a new tunnel using which is connected to the connection or
+ * connection group identifier by the given ID. Client information
+ * is specified in the {@code info} parameter.
+ *
+ * @param context
+ * The UserContext associated with the user for whom the tunnel is
+ * being created.
+ *
+ * @param id
+ * The ID of the connection or connection group being connected to. For
+ * connections, this will be of the form "c/IDENTIFIER", where
+ * IDENTIFIER is the connection identifier. For connection groups, this
+ * will be of the form "g/IDENTIFIER", where IDENTIFIER is the
+ * connection group identifier.
+ *
+ * @param info
+ * Information describing the connected Guacamole client.
+ *
+ * @return
+ * A new tunnel, connected as required by the request.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while creating the tunnel.
+ */
+ protected GuacamoleTunnel createConnectedTunnel(UserContext context, String id,
+ GuacamoleClientInformation info) throws GuacamoleException {
+
+ // Determine ID type
+ TunnelRequest.IdentifierType id_type = TunnelRequest.IdentifierType.getType(id);
+ if (id_type == null)
+ throw new GuacamoleClientException("Illegal identifier - unknown type.");
+
+ // Remove prefix
+ id = id.substring(id_type.PREFIX.length());
+
+ // Create connected tunnel from identifier
GuacamoleTunnel tunnel;
switch (id_type) {
@@ -211,7 +235,6 @@ public class TunnelRequestService {
case CONNECTION: {
// Get connection directory
- UserContext context = session.getUserContext();
Directory directory = context.getConnectionDirectory();
// Get authorized connection
@@ -231,7 +254,6 @@ public class TunnelRequestService {
case CONNECTION_GROUP: {
// Get connection group directory
- UserContext context = session.getUserContext();
Directory directory = context.getConnectionGroupDirectory();
// Get authorized connection group
@@ -253,7 +275,33 @@ public class TunnelRequestService {
}
- // Track tunnel open/close
+ return tunnel;
+
+ }
+
+ /**
+ * Associates the given tunnel with the given session, returning a wrapped
+ * version of the same tunnel which automatically handles closure and
+ * removal from the session.
+ *
+ * @param tunnel
+ * The connected tunnel to wrap and monitor.
+ *
+ * @param session
+ * The Guacamole session to associate the tunnel with.
+ *
+ * @return
+ * A new tunnel, associated with the given session, which delegates all
+ * functionality to the given tunnel while monitoring and automatically
+ * handling closure.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while obtaining the tunnel.
+ */
+ protected GuacamoleTunnel createAssociatedTunnel(final GuacamoleSession session,
+ GuacamoleTunnel tunnel) throws GuacamoleException {
+
+ // Monitor tunnel closure and data
GuacamoleTunnel monitoredTunnel = new DelegatingGuacamoleTunnel(tunnel) {
@Override
@@ -263,9 +311,7 @@ public class TunnelRequestService {
try {
if (GuacamoleProperties.getProperty(ClipboardRESTService.INTEGRATION_ENABLED, false)) {
- GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
ClipboardState clipboard = session.getClipboardState();
-
return new MonitoringGuacamoleReader(clipboard, super.acquireReader());
}
@@ -277,29 +323,18 @@ public class TunnelRequestService {
// Pass through by default.
return super.acquireReader();
-
+
}
@Override
public void close() throws GuacamoleException {
- // Get session - just close if session does not exist
- GuacamoleSession session;
- try {
- session = authenticationService.getGuacamoleSession(authToken);
- }
- catch (GuacamoleUnauthorizedException e) {
- logger.debug("Session destroyed prior to tunnel closure.", e);
- super.close();
- return;
- }
-
- // If we have a session, signal listeners
+ // Signal listeners
if (!notifyClose(session, this))
throw new GuacamoleException("Tunnel close canceled by listener.");
session.removeTunnel(getUUID().toString());
-
+
// Close if no exception due to listener
super.close();
@@ -313,10 +348,42 @@ public class TunnelRequestService {
return null;
}
+ // Associate tunnel with session
session.addTunnel(monitoredTunnel);
return monitoredTunnel;
+
+ }
+
+ /**
+ * Creates a new tunnel using the parameters and credentials present in
+ * the given request.
+ *
+ * @param request
+ * The request describing the tunnel to create.
+ *
+ * @return
+ * The created tunnel, or null if the tunnel could not be created.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while creating the tunnel.
+ */
+ public GuacamoleTunnel createTunnel(TunnelRequest request)
+ throws GuacamoleException {
+
+ // Get auth token and session
+ final String authToken = request.getParameter("authToken");
+ final GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
+
+ // Get client information and connection ID from request
+ final String id = request.getParameter("id");
+ final GuacamoleClientInformation info = getClientInformation(request);
+
+ // Create connected tunnel using provided connection ID and client information
+ final GuacamoleTunnel tunnel = createConnectedTunnel(session.getUserContext(), id, info);
+
+ // Associate tunnel with session
+ return createAssociatedTunnel(session, tunnel);
}
}
-
diff --git a/guacamole/src/main/webapp/translations/en_US.json b/guacamole/src/main/webapp/translations/en_US.json
index da003fd38..0b7fa7249 100644
--- a/guacamole/src/main/webapp/translations/en_US.json
+++ b/guacamole/src/main/webapp/translations/en_US.json
@@ -310,6 +310,7 @@
"FIELD_OPTION_SERVER_LAYOUT_EN_US_QWERTY" : "US English (Qwerty)",
"FIELD_OPTION_SERVER_LAYOUT_FAILSAFE" : "Unicode",
"FIELD_OPTION_SERVER_LAYOUT_FR_FR_AZERTY" : "French (Azerty)",
+ "FIELD_OPTION_SERVER_LAYOUT_IT_IT_QWERTY" : "Italian (Qwerty)",
"FIELD_OPTION_SERVER_LAYOUT_SV_SE_QWERTY" : "Swedish (Qwerty)",
"NAME" : "RDP"