mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-10-27 15:13:07 +00:00
GUAC-442: Tie new WebSocket implementation into authentication layer. Generalize tunnel requests.
This commit is contained in:
@@ -42,66 +42,9 @@ public class BasicGuacamoleTunnelServlet extends GuacamoleHTTPTunnelServlet {
|
|||||||
*/
|
*/
|
||||||
private static final Logger logger = LoggerFactory.getLogger(BasicGuacamoleTunnelServlet.class);
|
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
|
@Override
|
||||||
protected GuacamoleTunnel doConnect(HttpServletRequest request) throws GuacamoleException {
|
protected GuacamoleTunnel doConnect(HttpServletRequest request) throws GuacamoleException {
|
||||||
return BasicTunnelRequestUtility.createTunnel(request);
|
return BasicTunnelRequestUtility.createTunnel(new HTTPTunnelRequest(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,9 +22,8 @@
|
|||||||
|
|
||||||
package org.glyptodon.guacamole.net.basic;
|
package org.glyptodon.guacamole.net.basic;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import java.util.List;
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
import org.glyptodon.guacamole.GuacamoleClientException;
|
import org.glyptodon.guacamole.GuacamoleClientException;
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
@@ -63,63 +62,6 @@ public class BasicTunnelRequestUtility {
|
|||||||
*/
|
*/
|
||||||
private static final Logger logger = LoggerFactory.getLogger(BasicTunnelRequestUtility.class);
|
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
|
* Notifies all listeners in the given collection that a tunnel has been
|
||||||
* connected.
|
* connected.
|
||||||
@@ -200,18 +142,21 @@ public class BasicTunnelRequestUtility {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new tunnel using the parameters and credentials present in
|
* Creates a new tunnel using the parameters and credentials present in
|
||||||
* the given request.
|
* 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.
|
* @return The created tunnel, or null if the tunnel could not be created.
|
||||||
* @throws GuacamoleException If an error occurs while creating the tunnel.
|
* @throws GuacamoleException If an error occurs while creating the tunnel.
|
||||||
*/
|
*/
|
||||||
public static GuacamoleTunnel createTunnel(HttpServletRequest request)
|
public static GuacamoleTunnel createTunnel(TunnelRequest request)
|
||||||
throws GuacamoleException {
|
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
|
// Get listeners
|
||||||
final SessionListenerCollection listeners;
|
final SessionListenerCollection listeners;
|
||||||
@@ -225,7 +170,7 @@ public class BasicTunnelRequestUtility {
|
|||||||
|
|
||||||
// Get ID of connection
|
// Get ID of connection
|
||||||
String id = request.getParameter("id");
|
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
|
// Do not continue if unable to determine type
|
||||||
if (id_type == null)
|
if (id_type == null)
|
||||||
@@ -266,14 +211,14 @@ public class BasicTunnelRequestUtility {
|
|||||||
info.setOptimalResolution(Integer.parseInt(dpi));
|
info.setOptimalResolution(Integer.parseInt(dpi));
|
||||||
|
|
||||||
// Add audio mimetypes
|
// Add audio mimetypes
|
||||||
String[] audio_mimetypes = request.getParameterValues("audio");
|
List<String> audio_mimetypes = request.getParameterValues("audio");
|
||||||
if (audio_mimetypes != null)
|
if (audio_mimetypes != null)
|
||||||
info.getAudioMimetypes().addAll(Arrays.asList(audio_mimetypes));
|
info.getAudioMimetypes().addAll(audio_mimetypes);
|
||||||
|
|
||||||
// Add video mimetypes
|
// Add video mimetypes
|
||||||
String[] video_mimetypes = request.getParameterValues("video");
|
List<String> video_mimetypes = request.getParameterValues("video");
|
||||||
if (video_mimetypes != null)
|
if (video_mimetypes != null)
|
||||||
info.getVideoMimetypes().addAll(Arrays.asList(video_mimetypes));
|
info.getVideoMimetypes().addAll(video_mimetypes);
|
||||||
|
|
||||||
// Create connected socket from identifier
|
// Create connected socket from identifier
|
||||||
GuacamoleSocket socket;
|
GuacamoleSocket socket;
|
||||||
@@ -295,7 +240,7 @@ public class BasicTunnelRequestUtility {
|
|||||||
|
|
||||||
// Connect socket
|
// Connect socket
|
||||||
socket = connection.connect(info);
|
socket = connection.connect(info);
|
||||||
logger.info("Successful connection from {} to \"{}\".", request.getRemoteAddr(), id);
|
logger.info("Successful connection from to \"{}\".", id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,7 +260,7 @@ public class BasicTunnelRequestUtility {
|
|||||||
|
|
||||||
// Connect socket
|
// Connect socket
|
||||||
socket = group.connect(info);
|
socket = group.connect(info);
|
||||||
logger.info("Successful connection from {} to group \"{}\".", request.getRemoteAddr(), id);
|
logger.info("Successful connection to group \"{}\".", id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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<String> getParameterValues(String name) {
|
||||||
|
return Arrays.asList(request.getParameterValues(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<String> getParameterValues(String name);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
||||||
import org.glyptodon.guacamole.net.basic.BasicTunnelRequestUtility;
|
import org.glyptodon.guacamole.net.basic.BasicTunnelRequestUtility;
|
||||||
|
import org.glyptodon.guacamole.net.basic.HTTPTunnelRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tunnel servlet implementation which uses WebSocket as a tunnel backend,
|
* Tunnel servlet implementation which uses WebSocket as a tunnel backend,
|
||||||
@@ -37,7 +38,7 @@ public class BasicGuacamoleWebSocketTunnelServlet extends GuacamoleWebSocketTunn
|
|||||||
@Override
|
@Override
|
||||||
protected GuacamoleTunnel doConnect(HttpServletRequest request)
|
protected GuacamoleTunnel doConnect(HttpServletRequest request)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
return BasicTunnelRequestUtility.createTunnel(request);
|
return BasicTunnelRequestUtility.createTunnel(new HTTPTunnelRequest(request));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<String, Object> 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<String, Object> 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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<String, List<String>> 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<String> values = getParameterValues(name);
|
||||||
|
if (values == null || values.isEmpty())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// Return first parameter value arbitrarily
|
||||||
|
return values.get(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getParameterValues(String name) {
|
||||||
|
return handshakeParameters.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -26,6 +26,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
import org.glyptodon.guacamole.GuacamoleException;
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
import org.glyptodon.guacamole.net.GuacamoleTunnel;
|
||||||
import org.glyptodon.guacamole.net.basic.BasicTunnelRequestUtility;
|
import org.glyptodon.guacamole.net.basic.BasicTunnelRequestUtility;
|
||||||
|
import org.glyptodon.guacamole.net.basic.HTTPTunnelRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tunnel servlet implementation which uses WebSocket as a tunnel backend,
|
* Tunnel servlet implementation which uses WebSocket as a tunnel backend,
|
||||||
@@ -37,7 +38,7 @@ public class BasicGuacamoleWebSocketTunnelServlet extends GuacamoleWebSocketTunn
|
|||||||
@Override
|
@Override
|
||||||
protected GuacamoleTunnel doConnect(HttpServletRequest request)
|
protected GuacamoleTunnel doConnect(HttpServletRequest request)
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
return BasicTunnelRequestUtility.createTunnel(request);
|
return BasicTunnelRequestUtility.createTunnel(new HTTPTunnelRequest(request));
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user