in extensions/guacamole-auth-json/src/main/java/org/apache/guacamole/auth/json/connection/ConnectionService.java [169:305]
public GuacamoleTunnel connect(UserData.Connection connection,
GuacamoleClientInformation info, Map<String, String> tokens) throws GuacamoleException {
// Retrieve proxy configuration from environment
GuacamoleProxyConfiguration proxyConfig = environment.getDefaultGuacamoleProxyConfiguration();
// Get guacd connection parameters
String hostname = proxyConfig.getHostname();
int port = proxyConfig.getPort();
// Generate and verify connection configuration
GuacamoleConfiguration filteredConfig = getConfiguration(connection);
if (filteredConfig == null) {
logger.debug("Configuration for connection could not be "
+ "generated. Perhaps the connection being joined is not "
+ "active?");
throw new GuacamoleResourceNotFoundException("No such connection");
}
// Apply tokens to config parameters
new TokenFilter(tokens).filterValues(filteredConfig.getParameters());
// Determine socket type based on required encryption method
final ConfiguredGuacamoleSocket socket;
switch (proxyConfig.getEncryptionMethod()) {
// If guacd requires SSL, use it
case SSL:
socket = new ConfiguredGuacamoleSocket(
new SSLGuacamoleSocket(hostname, port),
filteredConfig, info
);
break;
// Connect directly via TCP if encryption is not enabled
case NONE:
socket = new ConfiguredGuacamoleSocket(
new InetGuacamoleSocket(hostname, port),
filteredConfig, info
);
break;
// Abort if encryption method is unknown
default:
throw new GuacamoleServerException("Unimplemented encryption method.");
}
final GuacamoleTunnel tunnel;
// If the current connection is not being tracked (no ID) just use a
// normal, non-tracking tunnel
final String id = connection.getId();
if (id == null)
tunnel = new SimpleGuacamoleTunnel(socket);
// Otherwise, create a tunnel with proper tracking which can be joined
else {
// Allow connection to be joined
final String connectionID = socket.getConnectionID();
final Collection<GuacamoleTunnel> existingTunnels = shadowers.putIfAbsent(connectionID,
Collections.synchronizedList(new ArrayList<>()));
// Duplicate connection IDs cannot exist
assert(existingTunnels == null);
// If the current connection is intended to be tracked (an ID was
// provided), but a connection is already in progress with that ID,
// log a warning that the original connection will no longer be tracked
String activeConnection = activeConnections.put(id, connectionID);
if (activeConnection != null)
logger.warn("A connection with ID \"{}\" is already in progress, "
+ "but another attempt to use this ID has been made. The "
+ "original connection will no longer be joinable.", id);
// Return a tunnel which automatically tracks the active connection
tunnel = new SimpleGuacamoleTunnel(new GuacamoleSocket() {
@Override
public GuacamoleReader getReader() {
return socket.getReader();
}
@Override
public GuacamoleWriter getWriter() {
return socket.getWriter();
}
@Override
public void close() throws GuacamoleException {
// Stop connection from being joined further
activeConnections.remove(id, connectionID);
// Close all connections sharing the closed connection
Collection<GuacamoleTunnel> tunnels = shadowers.remove(connectionID);
if (tunnels != null)
closeAll(tunnels);
socket.close();
}
@Override
public boolean isOpen() {
return socket.isOpen();
}
});
}
// Track tunnels which join connections, such that they can be
// automatically closed when the joined connection closes
String joinedConnection = filteredConfig.getConnectionID();
if (joinedConnection != null) {
// Track shadower of joined connection if possible
Collection<GuacamoleTunnel> tunnels = shadowers.get(joinedConnection);
if (tunnels != null)
tunnels.add(tunnel);
// Close this tunnel in ALL CASES if the joined connection has
// closed. Note that it is insufficient to simply check whether the
// retrieved Collection is null here, as it may have been removed
// after retrieval. We must ensure that the tunnel is closed in any
// case where it will not automatically be closed due to the
// closure of the shadowed connection.
if (!shadowers.containsKey(joinedConnection))
tunnel.close();
}
return tunnel;
}