GUACAMOLE-221: Expose underlying protocol at tunnel level.

This commit is contained in:
Virtually Nick
2020-11-25 18:54:18 -05:00
committed by GitHub
12 changed files with 297 additions and 165 deletions

View File

@@ -201,87 +201,52 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
ModeledConnectionGroup connectionGroup); ModeledConnectionGroup connectionGroup);
/** /**
* Returns a guacamole configuration containing the protocol and parameters * Returns a GuacamoleConfiguration which connects to the given connection.
* from the given connection. If the ID of an active connection is * If the ID of an active connection is provided, that active connection
* provided, that connection will be joined instead of starting a new * will be joined rather than establishing an entirely new connection. If
* primary connection. If tokens are used in the connection parameter * a sharing profile is provided, the parameters associated with that
* values, credentials from the given user will be substituted * sharing profile will be used to define the access provided to the user
* appropriately. * accessing the shared connection.
*
* @param user
* The user whose credentials should be used if necessary.
* *
* @param connection * @param connection
* The connection whose protocol and parameters should be added to the * The connection that the user is connecting to.
* returned configuration.
* *
* @param connectionID * @param connectionID
* The ID of the active connection to be joined, as returned by guacd, * The ID of the active connection being joined, as provided by guacd
* or null if a new primary connection should be established. * when the original connection was established, or null if a new
* * connection should be established instead.
* @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.
* *
* @param sharingProfile * @param sharingProfile
* The sharing profile whose associated parameters dictate the level * The sharing profile whose associated parameters dictate the level
* of access granted to the user joining the connection. * of access granted to the user joining the connection, or null if the
* * parameters associated with the connection should be used.
* @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.
* *
* @return * @return
* A GuacamoleConfiguration containing the protocol and parameters from * A GuacamoleConfiguration defining the requested, possibly shared
* the given connection. * connection.
*/ */
private GuacamoleConfiguration getGuacamoleConfiguration(RemoteAuthenticatedUser user, private GuacamoleConfiguration getGuacamoleConfiguration(
ModeledSharingProfile sharingProfile, String connectionID) { ModeledConnection connection, String connectionID,
ModeledSharingProfile sharingProfile) {
ConnectionModel model = connection.getModel();
// Generate configuration from available data // Generate configuration from available data
GuacamoleConfiguration config = new GuacamoleConfiguration(); GuacamoleConfiguration config = new GuacamoleConfiguration();
config.setProtocol(model.getProtocol());
config.setConnectionID(connectionID); config.setConnectionID(connectionID);
// Set parameters from associated data // Set parameters from associated data
Collection<SharingProfileParameterModel> parameters = sharingProfileParameterMapper.select(sharingProfile.getIdentifier()); if (sharingProfile != null) {
for (SharingProfileParameterModel parameter : parameters) Collection<SharingProfileParameterModel> parameters = sharingProfileParameterMapper.select(sharingProfile.getIdentifier());
config.setParameter(parameter.getName(), parameter.getValue()); 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; return config;
@@ -488,7 +453,7 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
if (activeConnection.isPrimaryConnection()) { if (activeConnection.isPrimaryConnection()) {
activeConnections.put(connection.getIdentifier(), activeConnection); activeConnections.put(connection.getIdentifier(), activeConnection);
activeConnectionGroups.put(connection.getParentIdentifier(), 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 // If we ARE joining an active connection under the restrictions of
@@ -502,8 +467,7 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
// Build configuration from the sharing profile and the ID of // Build configuration from the sharing profile and the ID of
// the connection being joined // the connection being joined
config = getGuacamoleConfiguration(activeConnection.getUser(), config = getGuacamoleConfiguration(connection, connectionID, activeConnection.getSharingProfile());
activeConnection.getSharingProfile(), connectionID);
} }

View File

@@ -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. * Returns whether this tunnel is currently connected.
* *
@@ -119,6 +133,15 @@ Guacamole.Tunnel = function() {
*/ */
this.uuid = null; 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. * Fired whenever an error is encountered by the tunnel.
* *
@@ -706,7 +729,7 @@ Guacamole.HTTPTunnel = function(tunnelURL, crossDomain, extraTunnelHeaders) {
reset_timeout(); reset_timeout();
// Get UUID from response // Get UUID from response
tunnel.uuid = connect_xmlhttprequest.responseText; tunnel.setUUID(connect_xmlhttprequest.responseText);
// Mark as open // Mark as open
tunnel.setState(Guacamole.Tunnel.State.OPEN); tunnel.setState(Guacamole.Tunnel.State.OPEN);
@@ -1019,7 +1042,7 @@ Guacamole.WebSocketTunnel = function(tunnelURL) {
// Associate tunnel UUID if received // Associate tunnel UUID if received
if (opcode === Guacamole.Tunnel.INTERNAL_DATA_OPCODE) if (opcode === Guacamole.Tunnel.INTERNAL_DATA_OPCODE)
tunnel.uuid = elements[0]; tunnel.setUUID(elements[0]);
// Tunnel is now open and UUID is available // Tunnel is now open and UUID is available
tunnel.setState(Guacamole.Tunnel.State.OPEN); tunnel.setState(Guacamole.Tunnel.State.OPEN);
@@ -1155,11 +1178,18 @@ Guacamole.ChainedTunnel = function(tunnelChain) {
* @private * @private
*/ */
function commit_tunnel() { function commit_tunnel() {
tunnel.onstatechange = chained_tunnel.onstatechange; tunnel.onstatechange = chained_tunnel.onstatechange;
tunnel.oninstruction = chained_tunnel.oninstruction; tunnel.oninstruction = chained_tunnel.oninstruction;
tunnel.onerror = chained_tunnel.onerror; 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; committedTunnel = tunnel;
} }
// Wrap own onstatechange within current tunnel // Wrap own onstatechange within current tunnel

View File

@@ -57,14 +57,14 @@
<build> <build>
<plugins> <plugins>
<!-- Written for 1.6 --> <!-- Written for 1.8 -->
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version> <version>3.3</version>
<configuration> <configuration>
<source>1.6</source> <source>1.8</source>
<target>1.6</target> <target>1.8</target>
<compilerArgs> <compilerArgs>
<arg>-Xlint:all</arg> <arg>-Xlint:all</arg>
<arg>-Werror</arg> <arg>-Werror</arg>

View File

@@ -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();
}
}

View File

@@ -29,6 +29,24 @@ import org.apache.guacamole.io.GuacamoleWriter;
*/ */
public interface GuacamoleSocket { 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 * Returns a GuacamoleReader which can be used to read from the
* Guacamole instruction stream associated with the connection * Guacamole instruction stream associated with the connection

View File

@@ -24,6 +24,7 @@ import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleServerException; import org.apache.guacamole.GuacamoleServerException;
import org.apache.guacamole.io.GuacamoleReader; import org.apache.guacamole.io.GuacamoleReader;
import org.apache.guacamole.io.GuacamoleWriter; import org.apache.guacamole.io.GuacamoleWriter;
import org.apache.guacamole.net.DelegatingGuacamoleSocket;
import org.apache.guacamole.net.GuacamoleSocket; import org.apache.guacamole.net.GuacamoleSocket;
/** /**
@@ -36,12 +37,7 @@ import org.apache.guacamole.net.GuacamoleSocket;
* this GuacamoleSocket from manually controlling the initial protocol * this GuacamoleSocket from manually controlling the initial protocol
* handshake. * handshake.
*/ */
public class ConfiguredGuacamoleSocket implements GuacamoleSocket { public class ConfiguredGuacamoleSocket extends DelegatingGuacamoleSocket {
/**
* The wrapped socket.
*/
private GuacamoleSocket socket;
/** /**
* The configuration to use when performing the Guacamole protocol * The configuration to use when performing the Guacamole protocol
@@ -125,7 +121,7 @@ public class ConfiguredGuacamoleSocket implements GuacamoleSocket {
GuacamoleConfiguration config, GuacamoleConfiguration config,
GuacamoleClientInformation info) throws GuacamoleException { GuacamoleClientInformation info) throws GuacamoleException {
this.socket = socket; super(socket);
this.config = config; this.config = config;
// Get reader and writer // Get reader and writer
@@ -268,23 +264,8 @@ public class ConfiguredGuacamoleSocket implements GuacamoleSocket {
} }
@Override @Override
public GuacamoleWriter getWriter() { public String getProtocol() {
return socket.getWriter(); return getConfiguration().getProtocol();
}
@Override
public GuacamoleReader getReader() {
return socket.getReader();
}
@Override
public void close() throws GuacamoleException {
socket.close();
}
@Override
public boolean isOpen() {
return socket.isOpen();
} }
} }

View File

@@ -28,7 +28,7 @@ import org.apache.guacamole.GuacamoleUpstreamNotFoundException;
import org.apache.guacamole.GuacamoleUpstreamTimeoutException; import org.apache.guacamole.GuacamoleUpstreamTimeoutException;
import org.apache.guacamole.GuacamoleUpstreamUnavailableException; import org.apache.guacamole.GuacamoleUpstreamUnavailableException;
import org.apache.guacamole.io.GuacamoleReader; import org.apache.guacamole.io.GuacamoleReader;
import org.apache.guacamole.io.GuacamoleWriter; import org.apache.guacamole.net.DelegatingGuacamoleSocket;
import org.apache.guacamole.net.GuacamoleSocket; import org.apache.guacamole.net.GuacamoleSocket;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -40,7 +40,7 @@ import org.slf4j.LoggerFactory;
* constructor, allowing a different socket to be substituted prior to * constructor, allowing a different socket to be substituted prior to
* fulfilling the connection. * fulfilling the connection.
*/ */
public class FailoverGuacamoleSocket implements GuacamoleSocket { public class FailoverGuacamoleSocket extends DelegatingGuacamoleSocket {
/** /**
* Logger for this class. * Logger for this class.
@@ -54,11 +54,6 @@ public class FailoverGuacamoleSocket implements GuacamoleSocket {
*/ */
private static final int DEFAULT_INSTRUCTION_QUEUE_LIMIT = 131072; private static final int DEFAULT_INSTRUCTION_QUEUE_LIMIT = 131072;
/**
* The wrapped socket being used.
*/
private final GuacamoleSocket socket;
/** /**
* Queue of all instructions read while this FailoverGuacamoleSocket was * Queue of all instructions read while this FailoverGuacamoleSocket was
* being constructed. * being constructed.
@@ -158,6 +153,8 @@ public class FailoverGuacamoleSocket implements GuacamoleSocket {
final int instructionQueueLimit) final int instructionQueueLimit)
throws GuacamoleException, GuacamoleUpstreamException { throws GuacamoleException, GuacamoleUpstreamException {
super(socket);
int totalQueueSize = 0; int totalQueueSize = 0;
GuacamoleInstruction instruction; GuacamoleInstruction instruction;
@@ -189,8 +186,6 @@ public class FailoverGuacamoleSocket implements GuacamoleSocket {
} }
this.socket = socket;
} }
/** /**
@@ -230,7 +225,7 @@ public class FailoverGuacamoleSocket implements GuacamoleSocket {
@Override @Override
public boolean available() throws GuacamoleException { public boolean available() throws GuacamoleException {
return !instructionQueue.isEmpty() || socket.getReader().available(); return !instructionQueue.isEmpty() || getDelegateSocket().getReader().available();
} }
@Override @Override
@@ -244,7 +239,7 @@ public class FailoverGuacamoleSocket implements GuacamoleSocket {
return instruction.toString().toCharArray(); return instruction.toString().toCharArray();
} }
return socket.getReader().read(); return getDelegateSocket().getReader().read();
} }
@@ -258,7 +253,7 @@ public class FailoverGuacamoleSocket implements GuacamoleSocket {
if (!instructionQueue.isEmpty()) if (!instructionQueue.isEmpty())
return instructionQueue.remove(); return instructionQueue.remove();
return socket.getReader().readInstruction(); return getDelegateSocket().getReader().readInstruction();
} }
@@ -269,19 +264,4 @@ public class FailoverGuacamoleSocket implements GuacamoleSocket {
return queuedReader; return queuedReader;
} }
@Override
public GuacamoleWriter getWriter() {
return socket.getWriter();
}
@Override
public void close() throws GuacamoleException {
socket.close();
}
@Override
public boolean isOpen() {
return socket.isOpen();
}
} }

View File

@@ -19,21 +19,16 @@
package org.apache.guacamole.protocol; package org.apache.guacamole.protocol;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.io.GuacamoleReader; import org.apache.guacamole.io.GuacamoleReader;
import org.apache.guacamole.io.GuacamoleWriter; import org.apache.guacamole.io.GuacamoleWriter;
import org.apache.guacamole.net.DelegatingGuacamoleSocket;
import org.apache.guacamole.net.GuacamoleSocket; import org.apache.guacamole.net.GuacamoleSocket;
/** /**
* Implementation of GuacamoleSocket which allows individual instructions to be * Implementation of GuacamoleSocket which allows individual instructions to be
* intercepted, overridden, etc. * intercepted, overridden, etc.
*/ */
public class FilteredGuacamoleSocket implements GuacamoleSocket { public class FilteredGuacamoleSocket extends DelegatingGuacamoleSocket {
/**
* Wrapped GuacamoleSocket.
*/
private final GuacamoleSocket socket;
/** /**
* A reader for the wrapped GuacamoleSocket which may be filtered. * A reader for the wrapped GuacamoleSocket which may be filtered.
@@ -58,7 +53,8 @@ public class FilteredGuacamoleSocket implements GuacamoleSocket {
* instructions, if any. * instructions, if any.
*/ */
public FilteredGuacamoleSocket(GuacamoleSocket socket, GuacamoleFilter readFilter, GuacamoleFilter writeFilter) { public FilteredGuacamoleSocket(GuacamoleSocket socket, GuacamoleFilter readFilter, GuacamoleFilter writeFilter) {
this.socket = socket;
super(socket);
// Apply filter to reader // Apply filter to reader
if (readFilter != null) if (readFilter != null)
@@ -84,14 +80,4 @@ public class FilteredGuacamoleSocket implements GuacamoleSocket {
return writer; return writer;
} }
@Override
public void close() throws GuacamoleException {
socket.close();
}
@Override
public boolean isOpen() {
return socket.isOpen();
}
} }

View File

@@ -92,8 +92,7 @@ public class GuacamoleConfiguration implements Serializable {
/** /**
* Sets the ID of the connection being joined, if any. If no connection * Sets the ID of the connection being joined, if any. If no connection
* is being joined, this value must be omitted, and the protocol must be * is being joined, this value must be omitted.
* set instead.
* *
* @param connectionID The ID of the connection being joined. * @param connectionID The ID of the connection being joined.
*/ */
@@ -103,15 +102,34 @@ public class GuacamoleConfiguration implements Serializable {
/** /**
* Returns the name of the protocol to be used. * Returns the name of the protocol to be used.
* @return The name of the protocol to be used. *
* @return
* The name of the protocol to be used.
*/ */
public String getProtocol() { public String getProtocol() {
return protocol; return protocol;
} }
/** /**
* Sets the name of the protocol to be used. * Sets the name of the protocol to be used. If no connection is being
* @param protocol The name of the protocol to be used. * joined (a new connection is being established), this value must be set.
*
* <p>If a connection is being joined, <strong>this value should still be
* set</strong> to ensure that protocol-specific responses like the
* "required" and "argv" instructions can be understood in their proper
* context by other code that may consume this GuacamoleConfiguration like
* {@link ConfiguredGuacamoleSocket}.
*
* <p>If this value is unavailable or remains unset, it is still possible
* to join an established connection using
* {@link #setConnectionID(java.lang.String)}, however protocol-specific
* responses like the "required" and "argv" instructions might not be
* possible to handle correctly if the underlying protocol is not made
* available through some other means to the client receiving those
* responses.
*
* @param protocol
* The name of the protocol to be used.
*/ */
public void setProtocol(String protocol) { public void setProtocol(String protocol) {
this.protocol = protocol; this.protocol = protocol;

View File

@@ -24,6 +24,7 @@ import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject; import com.google.inject.assistedinject.AssistedInject;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue; import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
@@ -31,8 +32,10 @@ import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleResourceNotFoundException; import org.apache.guacamole.GuacamoleResourceNotFoundException;
import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.net.auth.ActiveConnection; import org.apache.guacamole.net.auth.ActiveConnection;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.protocols.ProtocolInfo;
import org.apache.guacamole.rest.activeconnection.APIActiveConnection; import org.apache.guacamole.rest.activeconnection.APIActiveConnection;
import org.apache.guacamole.rest.directory.DirectoryObjectResource; import org.apache.guacamole.rest.directory.DirectoryObjectResource;
import org.apache.guacamole.rest.directory.DirectoryObjectResourceFactory; import org.apache.guacamole.rest.directory.DirectoryObjectResourceFactory;
@@ -57,6 +60,12 @@ public class TunnelResource {
*/ */
private final UserTunnel tunnel; private final UserTunnel tunnel;
/**
* The Guacamole server environment.
*/
@Inject
private Environment environment;
/** /**
* A factory which can be used to create instances of resources representing * A factory which can be used to create instances of resources representing
* ActiveConnections. * ActiveConnections.
@@ -106,6 +115,39 @@ public class TunnelResource {
} }
/**
* Retrieves the underlying protocol used by the connection associated with
* this tunnel. If possible, the parameters available for that protocol are
* retrieved, as well.
*
* @return
* A ProtocolInfo object describing the protocol used by the connection
* associated with this tunnel.
*
* @throws GuacamoleException
* If the protocol used by the connection associated with this tunnel
* cannot be determined.
*/
@GET
@Path("protocol")
public ProtocolInfo getProtocol() throws GuacamoleException {
// Pull protocol name from underlying socket
String protocol = tunnel.getSocket().getProtocol();
if (protocol == null)
throw new GuacamoleResourceNotFoundException("Protocol of tunnel is not known/exposed.");
// If there is no such protocol defined, provide as much info as is
// known (just the name)
ProtocolInfo info = environment.getProtocol(protocol);
if (info == null)
return new ProtocolInfo(protocol);
// All protocol information for this tunnel is known
return info;
}
/** /**
* Intercepts and returns the entire contents of a specific stream. * Intercepts and returns the entire contents of a specific stream.
* *

View File

@@ -386,7 +386,16 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
status.code); status.code);
}); });
}; };
// Pull protocol-specific information from tunnel once tunnel UUID is
// known
tunnel.onuuid = function tunnelAssignedUUID(uuid) {
tunnelService.getProtocol(uuid).then(function protocolRetrieved(protocol) {
managedClient.protocol = protocol.name;
managedClient.forms = protocol.connectionForms;
}, requestService.WARN);
};
// Update connection state as tunnel state changes // Update connection state as tunnel state changes
tunnel.onstatechange = function tunnelStateChanged(state) { tunnel.onstatechange = function tunnelStateChanged(state) {
$rootScope.$evalAsync(function updateTunnelState() { $rootScope.$evalAsync(function updateTunnelState() {
@@ -612,14 +621,9 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
// If using a connection, pull connection name and protocol information // If using a connection, pull connection name and protocol information
if (clientIdentifier.type === ClientIdentifier.Types.CONNECTION) { if (clientIdentifier.type === ClientIdentifier.Types.CONNECTION) {
$q.all({ connectionService.getConnection(clientIdentifier.dataSource, clientIdentifier.id)
connection : connectionService.getConnection(clientIdentifier.dataSource, clientIdentifier.id), .then(function connectionRetrieved(connection) {
protocols : schemaService.getProtocols(clientIdentifier.dataSource) managedClient.name = managedClient.title = connection.name;
})
.then(function dataRetrieved(values) {
managedClient.name = managedClient.title = values.connection.name;
managedClient.protocol = values.connection.protocol;
managedClient.forms = values.protocols[values.connection.protocol].connectionForms;
}, requestService.WARN); }, requestService.WARN);
} }
@@ -640,14 +644,9 @@ angular.module('client').factory('ManagedClient', ['$rootScope', '$injector',
// Attempt to retrieve connection details only if the // Attempt to retrieve connection details only if the
// underlying connection is known // underlying connection is known
if (activeConnection.connectionIdentifier) { if (activeConnection.connectionIdentifier) {
$q.all({ connectionService.getConnection(clientIdentifier.dataSource, activeConnection.connectionIdentifier)
connection : connectionService.getConnection(clientIdentifier.dataSource, activeConnection.connectionIdentifier), .then(function connectionRetrieved(connection) {
protocols : schemaService.getProtocols(clientIdentifier.dataSource) managedClient.name = managedClient.title = connection.name;
})
.then(function dataRetrieved(values) {
managedClient.name = managedClient.title = values.connection.name;
managedClient.protocol = values.connection.protocol;
managedClient.forms = values.protocols[values.connection.protocol].connectionForms;
}, requestService.WARN); }, requestService.WARN);
} }

View File

@@ -79,6 +79,36 @@ angular.module('rest').factory('tunnelService', ['$injector',
}; };
/**
* Makes a request to the REST API to retrieve the underlying protocol of
* the connection associated with a particular tunnel, returning a promise
* that provides a @link{Protocol} object if successful.
*
* @param {String} tunnel
* The UUID of the tunnel associated with the Guacamole connection
* whose underlying protocol is being retrieved.
*
* @returns {Promise.<Protocol>}
* A promise which will resolve with a @link{Protocol} object upon
* success.
*/
service.getProtocol = function getProtocol(tunnel) {
// Build HTTP parameters set
var httpParameters = {
token : authenticationService.getCurrentToken()
};
// Retrieve the protocol details of the specified tunnel
return requestService({
method : 'GET',
url : 'api/session/tunnels/' + encodeURIComponent(tunnel)
+ '/protocol',
params : httpParameters
});
};
/** /**
* Retrieves the set of sharing profiles that the current user can use to * Retrieves the set of sharing profiles that the current user can use to
* share the active connection of the given tunnel. * share the active connection of the given tunnel.