From c30afba91de8e27cab723c9cb9e1ace019eb897a Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 9 Oct 2014 21:01:34 -0700 Subject: [PATCH] GUAC-442: Tie new WebSocket implementation into authentication layer. Generalize tunnel requests. --- .../basic/BasicGuacamoleTunnelServlet.java | 59 +-------- .../net/basic/BasicTunnelRequestUtility.java | 83 +++--------- .../net/basic/HTTPTunnelRequest.java | 67 ++++++++++ .../guacamole/net/basic/TunnelRequest.java | 118 ++++++++++++++++++ .../BasicGuacamoleWebSocketTunnelServlet.java | 3 +- ...BasicGuacamoleWebSocketTunnelEndpoint.java | 102 +++++++++++++++ .../websocket/jsr/WebSocketTunnelRequest.java | 82 ++++++++++++ .../BasicGuacamoleWebSocketTunnelServlet.java | 3 +- 8 files changed, 388 insertions(+), 129 deletions(-) create mode 100644 guacamole/src/main/java/org/glyptodon/guacamole/net/basic/HTTPTunnelRequest.java create mode 100644 guacamole/src/main/java/org/glyptodon/guacamole/net/basic/TunnelRequest.java create mode 100644 guacamole/src/main/java/org/glyptodon/guacamole/net/basic/websocket/jsr/BasicGuacamoleWebSocketTunnelEndpoint.java create mode 100644 guacamole/src/main/java/org/glyptodon/guacamole/net/basic/websocket/jsr/WebSocketTunnelRequest.java diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/BasicGuacamoleTunnelServlet.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/BasicGuacamoleTunnelServlet.java index fafb12d48..f37c76c05 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/BasicGuacamoleTunnelServlet.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/BasicGuacamoleTunnelServlet.java @@ -42,66 +42,9 @@ public class BasicGuacamoleTunnelServlet extends GuacamoleHTTPTunnelServlet { */ private static final Logger logger = LoggerFactory.getLogger(BasicGuacamoleTunnelServlet.class); - /** - * All supported identifier types. - */ - public static enum IdentifierType { - - /** - * The unique identifier of a connection. - */ - CONNECTION("c/"), - - /** - * The unique identifier of a connection group. - */ - CONNECTION_GROUP("g/"); - - /** - * The prefix which precedes an identifier of this type. - */ - final String PREFIX; - - /** - * Defines an IdentifierType having the given prefix. - * @param prefix The prefix which will precede any identifier of this - * type, thus differentiating it from other identifier - * types. - */ - IdentifierType(String prefix) { - PREFIX = prefix; - } - - /** - * Given an identifier, determines the corresponding identifier type. - * - * @param identifier The identifier whose type should be identified. - * @return The identified identifier type. - */ - static IdentifierType getType(String identifier) { - - // If null, no known identifier - if (identifier == null) - return null; - - // Connection identifiers - if (identifier.startsWith(CONNECTION.PREFIX)) - return CONNECTION; - - // Connection group identifiers - if (identifier.startsWith(CONNECTION_GROUP.PREFIX)) - return CONNECTION_GROUP; - - // Otherwise, unknown - return null; - - } - - }; - @Override protected GuacamoleTunnel doConnect(HttpServletRequest request) throws GuacamoleException { - return BasicTunnelRequestUtility.createTunnel(request); + return BasicTunnelRequestUtility.createTunnel(new HTTPTunnelRequest(request)); } } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/BasicTunnelRequestUtility.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/BasicTunnelRequestUtility.java index 04efc8ff5..f102d073b 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/BasicTunnelRequestUtility.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/BasicTunnelRequestUtility.java @@ -22,9 +22,8 @@ package org.glyptodon.guacamole.net.basic; -import java.util.Arrays; import java.util.Collection; -import javax.servlet.http.HttpServletRequest; +import java.util.List; import javax.servlet.http.HttpSession; import org.glyptodon.guacamole.GuacamoleClientException; import org.glyptodon.guacamole.GuacamoleException; @@ -63,63 +62,6 @@ public class BasicTunnelRequestUtility { */ private static final Logger logger = LoggerFactory.getLogger(BasicTunnelRequestUtility.class); - /** - * All supported identifier types. - */ - private static enum IdentifierType { - - /** - * The unique identifier of a connection. - */ - CONNECTION("c/"), - - /** - * The unique identifier of a connection group. - */ - CONNECTION_GROUP("g/"); - - /** - * The prefix which precedes an identifier of this type. - */ - final String PREFIX; - - /** - * Defines an IdentifierType having the given prefix. - * @param prefix The prefix which will precede any identifier of this - * type, thus differentiating it from other identifier - * types. - */ - IdentifierType(String prefix) { - PREFIX = prefix; - } - - /** - * Given an identifier, determines the corresponding identifier type. - * - * @param identifier The identifier whose type should be identified. - * @return The identified identifier type. - */ - static IdentifierType getType(String identifier) { - - // If null, no known identifier - if (identifier == null) - return null; - - // Connection identifiers - if (identifier.startsWith(CONNECTION.PREFIX)) - return CONNECTION; - - // Connection group identifiers - if (identifier.startsWith(CONNECTION_GROUP.PREFIX)) - return CONNECTION_GROUP; - - // Otherwise, unknown - return null; - - } - - }; - /** * Notifies all listeners in the given collection that a tunnel has been * connected. @@ -200,18 +142,21 @@ public class BasicTunnelRequestUtility { } + /** * Creates a new tunnel using the parameters and credentials present in * the given request. * - * @param request The HttpServletRequest describing the tunnel to create. + * @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 static GuacamoleTunnel createTunnel(HttpServletRequest request) + public static GuacamoleTunnel createTunnel(TunnelRequest request) throws GuacamoleException { - HttpSession httpSession = request.getSession(true); + HttpSession httpSession = request.getSession(); + if (httpSession == null) + throw new GuacamoleSecurityException("Cannot connect - user not logged in."); // Get listeners final SessionListenerCollection listeners; @@ -225,7 +170,7 @@ public class BasicTunnelRequestUtility { // Get ID of connection String id = request.getParameter("id"); - IdentifierType id_type = IdentifierType.getType(id); + TunnelRequest.IdentifierType id_type = TunnelRequest.IdentifierType.getType(id); // Do not continue if unable to determine type if (id_type == null) @@ -266,14 +211,14 @@ public class BasicTunnelRequestUtility { info.setOptimalResolution(Integer.parseInt(dpi)); // Add audio mimetypes - String[] audio_mimetypes = request.getParameterValues("audio"); + List audio_mimetypes = request.getParameterValues("audio"); if (audio_mimetypes != null) - info.getAudioMimetypes().addAll(Arrays.asList(audio_mimetypes)); + info.getAudioMimetypes().addAll(audio_mimetypes); // Add video mimetypes - String[] video_mimetypes = request.getParameterValues("video"); + List video_mimetypes = request.getParameterValues("video"); if (video_mimetypes != null) - info.getVideoMimetypes().addAll(Arrays.asList(video_mimetypes)); + info.getVideoMimetypes().addAll(video_mimetypes); // Create connected socket from identifier GuacamoleSocket socket; @@ -295,7 +240,7 @@ public class BasicTunnelRequestUtility { // Connect socket socket = connection.connect(info); - logger.info("Successful connection from {} to \"{}\".", request.getRemoteAddr(), id); + logger.info("Successful connection from to \"{}\".", id); break; } @@ -315,7 +260,7 @@ public class BasicTunnelRequestUtility { // Connect socket socket = group.connect(info); - logger.info("Successful connection from {} to group \"{}\".", request.getRemoteAddr(), id); + logger.info("Successful connection to group \"{}\".", id); break; } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/HTTPTunnelRequest.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/HTTPTunnelRequest.java new file mode 100644 index 000000000..7185d89f4 --- /dev/null +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/HTTPTunnelRequest.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package org.glyptodon.guacamole.net.basic; + +import java.util.Arrays; +import java.util.List; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +/** + * HTTP-specific implementation of TunnelRequest. + * + * @author Michael Jumper + */ +public class HTTPTunnelRequest implements TunnelRequest { + + /** + * The wrapped HttpServletRequest. + */ + private final HttpServletRequest request; + + /** + * Creates a TunnelRequest implementation which delegates parameter and + * session retrieval to the given HttpServletRequest. + * + * @param request The HttpServletRequest to wrap. + */ + public HTTPTunnelRequest(HttpServletRequest request) { + this.request = request; + } + + @Override + public HttpSession getSession() { + return request.getSession(); + } + + @Override + public String getParameter(String name) { + return request.getParameter(name); + } + + @Override + public List getParameterValues(String name) { + return Arrays.asList(request.getParameterValues(name)); + } + +} diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/TunnelRequest.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/TunnelRequest.java new file mode 100644 index 000000000..477b1a946 --- /dev/null +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/TunnelRequest.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +package org.glyptodon.guacamole.net.basic; + +import java.util.List; +import javax.servlet.http.HttpSession; + +/** + * Request interface which provides only the functions absolutely required + * to retrieve and connect to a tunnel. + * + * @author Michael Jumper + */ +public interface TunnelRequest { + + /** + * All supported identifier types. + */ + public static enum IdentifierType { + + /** + * The unique identifier of a connection. + */ + CONNECTION("c/"), + + /** + * The unique identifier of a connection group. + */ + CONNECTION_GROUP("g/"); + + /** + * The prefix which precedes an identifier of this type. + */ + final String PREFIX; + + /** + * Defines an IdentifierType having the given prefix. + * @param prefix The prefix which will precede any identifier of this + * type, thus differentiating it from other identifier + * types. + */ + IdentifierType(String prefix) { + PREFIX = prefix; + } + + /** + * Given an identifier, determines the corresponding identifier type. + * + * @param identifier The identifier whose type should be identified. + * @return The identified identifier type. + */ + static IdentifierType getType(String identifier) { + + // If null, no known identifier + if (identifier == null) + return null; + + // Connection identifiers + if (identifier.startsWith(CONNECTION.PREFIX)) + return CONNECTION; + + // Connection group identifiers + if (identifier.startsWith(CONNECTION_GROUP.PREFIX)) + return CONNECTION_GROUP; + + // Otherwise, unknown + return null; + + } + + }; + + /** + * Returns the current HTTP session, or null if no session yet exists. + * + * @return The current HTTP session, or null if no session yet exists. + */ + public HttpSession getSession(); + + /** + * Returns the value of the parameter having the given name. + * + * @param name The name of the parameter to return. + * @return The value of the parameter having the given name, or null + * if no such parameter was specified. + */ + public String getParameter(String name); + + /** + * Returns a list of all values specified for the given parameter. + * + * @param name The name of the parameter to return. + * @return All values of the parameter having the given name , or null + * if no such parameter was specified. + */ + public List getParameterValues(String name); + +} diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/websocket/jetty/BasicGuacamoleWebSocketTunnelServlet.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/websocket/jetty/BasicGuacamoleWebSocketTunnelServlet.java index 38c68b6f3..0a9d680c5 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/websocket/jetty/BasicGuacamoleWebSocketTunnelServlet.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/websocket/jetty/BasicGuacamoleWebSocketTunnelServlet.java @@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletRequest; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.net.GuacamoleTunnel; import org.glyptodon.guacamole.net.basic.BasicTunnelRequestUtility; +import org.glyptodon.guacamole.net.basic.HTTPTunnelRequest; /** * Tunnel servlet implementation which uses WebSocket as a tunnel backend, @@ -37,7 +38,7 @@ public class BasicGuacamoleWebSocketTunnelServlet extends GuacamoleWebSocketTunn @Override protected GuacamoleTunnel doConnect(HttpServletRequest request) throws GuacamoleException { - return BasicTunnelRequestUtility.createTunnel(request); + return BasicTunnelRequestUtility.createTunnel(new HTTPTunnelRequest(request)); } } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/websocket/jsr/BasicGuacamoleWebSocketTunnelEndpoint.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/websocket/jsr/BasicGuacamoleWebSocketTunnelEndpoint.java new file mode 100644 index 000000000..716f7f7a3 --- /dev/null +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/websocket/jsr/BasicGuacamoleWebSocketTunnelEndpoint.java @@ -0,0 +1,102 @@ +/* + * 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. + */ + +package org.glyptodon.guacamole.net.basic.websocket.jsr; + +import java.util.Map; +import javax.websocket.EndpointConfig; +import javax.websocket.HandshakeResponse; +import javax.websocket.Session; +import javax.websocket.server.HandshakeRequest; +import javax.websocket.server.ServerEndpoint; +import javax.websocket.server.ServerEndpointConfig; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.net.GuacamoleTunnel; +import org.glyptodon.guacamole.net.basic.BasicTunnelRequestUtility; + +/** + * Tunnel implementation which uses WebSocket as a tunnel backend, rather than + * HTTP, properly parsing connection IDs included in the connection request. + */ +@ServerEndpoint(value = "/websocket-tunnel", + subprotocols = {"guacamole"}, + configurator = BasicGuacamoleWebSocketTunnelEndpoint.Configurator.class) +public class BasicGuacamoleWebSocketTunnelEndpoint extends GuacamoleWebSocketTunnelEndpoint { + + /** + * Unique string which shall be used to store the GuacamoleTunnel + * associated with a WebSocket connection. + */ + private static final String TUNNEL_USER_PROPERTY = "WS_GUAC_TUNNEL"; + + /** + * Unique string which shall be used to store any GuacamoleException that + * occurs while retrieving the tunnel during the handshake. + */ + private static final String ERROR_USER_PROPERTY = "WS_GUAC_TUNNEL_ERROR"; + + /** + * Configurator implementation which stores the requested GuacamoleTunnel + * within the user properties. The GuacamoleTunnel will be later retrieved + * during the connection process. + */ + public static class Configurator extends ServerEndpointConfig.Configurator { + + @Override + public void modifyHandshake(ServerEndpointConfig config, HandshakeRequest request, HandshakeResponse response) { + + super.modifyHandshake(config, request, response); + + // Attempt tunnel creation + Map userProperties = config.getUserProperties(); + userProperties.clear(); + try { + + // Store new tunnel within user properties + GuacamoleTunnel tunnel = BasicTunnelRequestUtility.createTunnel(new WebSocketTunnelRequest(request)); + if (tunnel != null) + userProperties.put(TUNNEL_USER_PROPERTY, tunnel); + + } + catch (GuacamoleException e) { + userProperties.put(ERROR_USER_PROPERTY, e); + } + + } + + } + + @Override + protected GuacamoleTunnel createTunnel(Session session, EndpointConfig config) throws GuacamoleException { + + // Throw any error that occurred during tunnel creation + Map userProperties = config.getUserProperties(); + GuacamoleException tunnelError = (GuacamoleException) userProperties.get(ERROR_USER_PROPERTY); + if (tunnelError != null) + throw tunnelError; + + // Return created tunnel, if any + return (GuacamoleTunnel) userProperties.get(TUNNEL_USER_PROPERTY); + + } + +} diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/websocket/jsr/WebSocketTunnelRequest.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/websocket/jsr/WebSocketTunnelRequest.java new file mode 100644 index 000000000..3b80b5a96 --- /dev/null +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/websocket/jsr/WebSocketTunnelRequest.java @@ -0,0 +1,82 @@ +/* + * 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. + */ + +package org.glyptodon.guacamole.net.basic.websocket.jsr; + +import java.util.List; +import java.util.Map; +import javax.servlet.http.HttpSession; +import javax.websocket.server.HandshakeRequest; +import org.glyptodon.guacamole.net.basic.TunnelRequest; + +/** + * WebSocket-specific implementation of TunnelRequest. + * + * @author Michael Jumper + */ +public class WebSocketTunnelRequest implements TunnelRequest { + + /** + * The wrapped HandshakeRequest. + */ + private final HandshakeRequest request; + + /** + * All parameters passed via HTTP to the WebSocket handshake. + */ + private final Map> handshakeParameters; + + /** + * Creates a TunnelRequest implementation which delegates parameter and + * session retrieval to the given HandshakeRequest. + * + * @param request The HandshakeRequest to wrap. + */ + public WebSocketTunnelRequest(HandshakeRequest request) { + this.request = request; + this.handshakeParameters = request.getParameterMap(); + } + + @Override + public HttpSession getSession() { + return (HttpSession) request.getHttpSession(); + } + + @Override + public String getParameter(String name) { + + // Pull list of values, if present + List values = getParameterValues(name); + if (values == null || values.isEmpty()) + return null; + + // Return first parameter value arbitrarily + return values.get(0); + + } + + @Override + public List getParameterValues(String name) { + return handshakeParameters.get(name); + } + +} diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/websocket/tomcat/BasicGuacamoleWebSocketTunnelServlet.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/websocket/tomcat/BasicGuacamoleWebSocketTunnelServlet.java index 32daff448..e54cf8bdb 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/websocket/tomcat/BasicGuacamoleWebSocketTunnelServlet.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/websocket/tomcat/BasicGuacamoleWebSocketTunnelServlet.java @@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletRequest; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.net.GuacamoleTunnel; import org.glyptodon.guacamole.net.basic.BasicTunnelRequestUtility; +import org.glyptodon.guacamole.net.basic.HTTPTunnelRequest; /** * Tunnel servlet implementation which uses WebSocket as a tunnel backend, @@ -37,7 +38,7 @@ public class BasicGuacamoleWebSocketTunnelServlet extends GuacamoleWebSocketTunn @Override protected GuacamoleTunnel doConnect(HttpServletRequest request) throws GuacamoleException { - return BasicTunnelRequestUtility.createTunnel(request); + return BasicTunnelRequestUtility.createTunnel(new HTTPTunnelRequest(request)); }; }