Skip to content

Commit

Permalink
GUACAMOLE-221: Expose underlying protocol at tunnel level.
Browse files Browse the repository at this point in the history
  • Loading branch information
necouchman authored Nov 25, 2020
2 parents 920d83f + d1de61d commit ecd385b
Show file tree
Hide file tree
Showing 12 changed files with 297 additions and 165 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -201,87 +201,52 @@ protected abstract void release(RemoteAuthenticatedUser user,
ModeledConnectionGroup connectionGroup);

/**
* Returns a guacamole configuration containing the protocol and parameters
* from the given connection. If the ID of an active connection is
* provided, that connection will be joined instead of starting a new
* primary connection. If tokens are used in the connection parameter
* values, credentials from the given user will be substituted
* appropriately.
*
* @param user
* The user whose credentials should be used if necessary.
* Returns a GuacamoleConfiguration which connects to the given connection.
* If the ID of an active connection is provided, that active connection
* will be joined rather than establishing an entirely new connection. If
* a sharing profile is provided, the parameters associated with that
* sharing profile will be used to define the access provided to the user
* accessing the shared connection.
*
* @param connection
* The connection whose protocol and parameters should be added to the
* returned configuration.
* The connection that the user is connecting to.
*
* @param connectionID
* The ID of the active connection to be joined, as returned by guacd,
* or null if a new primary connection should be established.
*
* @return
* A GuacamoleConfiguration containing the protocol and parameters from
* the given connection.
*/
private GuacamoleConfiguration getGuacamoleConfiguration(RemoteAuthenticatedUser user,
ModeledConnection connection, String connectionID) {

// Generate configuration from available data
GuacamoleConfiguration config = new GuacamoleConfiguration();

// Join existing active connection, if any
if (connectionID != null)
config.setConnectionID(connectionID);

// Set protocol from connection if not joining an active connection
else {
ConnectionModel model = connection.getModel();
config.setProtocol(model.getProtocol());
}

// Set parameters from associated data
Collection<ConnectionParameterModel> parameters = connectionParameterMapper.select(connection.getIdentifier());
for (ConnectionParameterModel parameter : parameters)
config.setParameter(parameter.getName(), parameter.getValue());

return config;

}

/**
* Returns a guacamole configuration which joins the active connection
* having the given ID, using the provided sharing profile to restrict the
* access provided to the user accessing the shared connection. If tokens
* are used in the connection parameter values of the sharing profile,
* credentials from the given user will be substituted appropriately.
*
* @param user
* The user whose credentials should be used if necessary.
* The ID of the active connection being joined, as provided by guacd
* when the original connection was established, or null if a new
* connection should be established instead.
*
* @param sharingProfile
* The sharing profile whose associated parameters dictate the level
* of access granted to the user joining the connection.
*
* @param connectionID
* The ID of the connection being joined, as provided by guacd when the
* original connection was established, or null if a new connection
* should be created instead.
* of access granted to the user joining the connection, or null if the
* parameters associated with the connection should be used.
*
* @return
* A GuacamoleConfiguration containing the protocol and parameters from
* the given connection.
* A GuacamoleConfiguration defining the requested, possibly shared
* connection.
*/
private GuacamoleConfiguration getGuacamoleConfiguration(RemoteAuthenticatedUser user,
ModeledSharingProfile sharingProfile, String connectionID) {
private GuacamoleConfiguration getGuacamoleConfiguration(
ModeledConnection connection, String connectionID,
ModeledSharingProfile sharingProfile) {

ConnectionModel model = connection.getModel();

// Generate configuration from available data
GuacamoleConfiguration config = new GuacamoleConfiguration();
config.setProtocol(model.getProtocol());
config.setConnectionID(connectionID);

// Set parameters from associated data
Collection<SharingProfileParameterModel> parameters = sharingProfileParameterMapper.select(sharingProfile.getIdentifier());
for (SharingProfileParameterModel parameter : parameters)
config.setParameter(parameter.getName(), parameter.getValue());
if (sharingProfile != null) {
Collection<SharingProfileParameterModel> parameters = sharingProfileParameterMapper.select(sharingProfile.getIdentifier());
for (SharingProfileParameterModel parameter : parameters)
config.setParameter(parameter.getName(), parameter.getValue());
}
else {
Collection<ConnectionParameterModel> parameters = connectionParameterMapper.select(connection.getIdentifier());
for (ConnectionParameterModel parameter : parameters)
config.setParameter(parameter.getName(), parameter.getValue());
}

return config;

Expand Down Expand Up @@ -488,7 +453,7 @@ private GuacamoleTunnel assignGuacamoleTunnel(ActiveConnectionRecord activeConne
if (activeConnection.isPrimaryConnection()) {
activeConnections.put(connection.getIdentifier(), activeConnection);
activeConnectionGroups.put(connection.getParentIdentifier(), activeConnection);
config = getGuacamoleConfiguration(activeConnection.getUser(), connection, activeConnection.getConnectionID());
config = getGuacamoleConfiguration(connection, activeConnection.getConnectionID(), null);
}

// If we ARE joining an active connection under the restrictions of
Expand All @@ -502,8 +467,7 @@ private GuacamoleTunnel assignGuacamoleTunnel(ActiveConnectionRecord activeConne

// Build configuration from the sharing profile and the ID of
// the connection being joined
config = getGuacamoleConfiguration(activeConnection.getUser(),
activeConnection.getSharingProfile(), connectionID);
config = getGuacamoleConfiguration(connection, connectionID, activeConnection.getSharingProfile());

}

Expand Down
36 changes: 33 additions & 3 deletions guacamole-common-js/src/main/webapp/modules/Tunnel.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,20 @@ Guacamole.Tunnel = function() {

};

/**
* Changes the stored UUID that uniquely identifies this tunnel, firing the
* onuuid event if a handler has been defined.
*
* @private
* @param {String} uuid
* The new state of this tunnel.
*/
this.setUUID = function setUUID(uuid) {
this.uuid = uuid;
if (this.onuuid)
this.onuuid(uuid);
};

/**
* Returns whether this tunnel is currently connected.
*
Expand Down Expand Up @@ -119,6 +133,15 @@ Guacamole.Tunnel = function() {
*/
this.uuid = null;

/**
* Fired when the UUID that uniquely identifies this tunnel is known.
*
* @event
* @param {String}
* The UUID uniquely identifying this tunnel.
*/
this.onuuid = null;

/**
* Fired whenever an error is encountered by the tunnel.
*
Expand Down Expand Up @@ -706,7 +729,7 @@ Guacamole.HTTPTunnel = function(tunnelURL, crossDomain, extraTunnelHeaders) {
reset_timeout();

// Get UUID from response
tunnel.uuid = connect_xmlhttprequest.responseText;
tunnel.setUUID(connect_xmlhttprequest.responseText);

// Mark as open
tunnel.setState(Guacamole.Tunnel.State.OPEN);
Expand Down Expand Up @@ -1019,7 +1042,7 @@ Guacamole.WebSocketTunnel = function(tunnelURL) {

// Associate tunnel UUID if received
if (opcode === Guacamole.Tunnel.INTERNAL_DATA_OPCODE)
tunnel.uuid = elements[0];
tunnel.setUUID(elements[0]);

// Tunnel is now open and UUID is available
tunnel.setState(Guacamole.Tunnel.State.OPEN);
Expand Down Expand Up @@ -1155,11 +1178,18 @@ Guacamole.ChainedTunnel = function(tunnelChain) {
* @private
*/
function commit_tunnel() {

tunnel.onstatechange = chained_tunnel.onstatechange;
tunnel.oninstruction = chained_tunnel.oninstruction;
tunnel.onerror = chained_tunnel.onerror;
chained_tunnel.uuid = tunnel.uuid;
tunnel.onuuid = chained_tunnel.onuuid;

// Assign UUID if already known
if (tunnel.uuid)
chained_tunnel.setUUID(tunnel.uuid);

committedTunnel = tunnel;

}

// Wrap own onstatechange within current tunnel
Expand Down
6 changes: 3 additions & 3 deletions guacamole-common/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,14 @@
<build>
<plugins>

<!-- Written for 1.6 -->
<!-- Written for 1.8 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<source>1.8</source>
<target>1.8</target>
<compilerArgs>
<arg>-Xlint:all</arg>
<arg>-Werror</arg>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.guacamole.net;

import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.io.GuacamoleReader;
import org.apache.guacamole.io.GuacamoleWriter;

/**
* GuacamoleSocket implementation which simply delegates all function calls to
* an underlying GuacamoleSocket.
*/
public class DelegatingGuacamoleSocket implements GuacamoleSocket {

/**
* The wrapped socket.
*/
private final GuacamoleSocket socket;

/**
* Wraps the given GuacamoleSocket such that all function calls against
* this DelegatingGuacamoleSocket will be delegated to it.
*
* @param socket
* The GuacamoleSocket to wrap.
*/
public DelegatingGuacamoleSocket(GuacamoleSocket socket) {
this.socket = socket;
}

/**
* Returns the underlying GuacamoleSocket wrapped by this
* DelegatingGuacamoleSocket.
*
* @return
* The GuacamoleSocket wrapped by this DelegatingGuacamoleSocket.
*/
protected GuacamoleSocket getDelegateSocket() {
return socket;
}

@Override
public String getProtocol() {
return socket.getProtocol();
}

@Override
public GuacamoleReader getReader() {
return socket.getReader();
}

@Override
public GuacamoleWriter getWriter() {
return socket.getWriter();
}

@Override
public void close() throws GuacamoleException {
socket.close();
}

@Override
public boolean isOpen() {
return socket.isOpen();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,24 @@
*/
public interface GuacamoleSocket {

/**
* Returns the name of the protocol to be used. If the protocol is not
* known or the implementation refuses to reveal the underlying protocol,
* null is returned.
*
* <p>Implementations <strong>should</strong> aim to expose the name of the
* underlying protocol, such that protocol-specific responses like the
* "required" and "argv" instructions can be handled correctly by code
* consuming the GuacamoleSocket.
*
* @return
* The name of the protocol to be used, or null if this information is
* not available.
*/
public default String getProtocol() {
return null;
}

/**
* Returns a GuacamoleReader which can be used to read from the
* Guacamole instruction stream associated with the connection
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.apache.guacamole.GuacamoleServerException;
import org.apache.guacamole.io.GuacamoleReader;
import org.apache.guacamole.io.GuacamoleWriter;
import org.apache.guacamole.net.DelegatingGuacamoleSocket;
import org.apache.guacamole.net.GuacamoleSocket;

/**
Expand All @@ -36,12 +37,7 @@
* this GuacamoleSocket from manually controlling the initial protocol
* handshake.
*/
public class ConfiguredGuacamoleSocket implements GuacamoleSocket {

/**
* The wrapped socket.
*/
private GuacamoleSocket socket;
public class ConfiguredGuacamoleSocket extends DelegatingGuacamoleSocket {

/**
* The configuration to use when performing the Guacamole protocol
Expand Down Expand Up @@ -125,7 +121,7 @@ public ConfiguredGuacamoleSocket(GuacamoleSocket socket,
GuacamoleConfiguration config,
GuacamoleClientInformation info) throws GuacamoleException {

this.socket = socket;
super(socket);
this.config = config;

// Get reader and writer
Expand Down Expand Up @@ -268,23 +264,8 @@ public GuacamoleProtocolVersion getProtocolVersion() {
}

@Override
public GuacamoleWriter getWriter() {
return socket.getWriter();
}

@Override
public GuacamoleReader getReader() {
return socket.getReader();
}

@Override
public void close() throws GuacamoleException {
socket.close();
}

@Override
public boolean isOpen() {
return socket.isOpen();
public String getProtocol() {
return getConfiguration().getProtocol();
}

}
Loading

0 comments on commit ecd385b

Please sign in to comment.