mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
GUACAMOLE-360: Add support for joining active connections to the database auth.
This commit is contained in:
@@ -91,15 +91,16 @@ public class ActiveConnectionService
|
||||
Collection<TrackedActiveConnection> activeConnections = new ArrayList<TrackedActiveConnection>(identifiers.size());
|
||||
for (ActiveConnectionRecord record : records) {
|
||||
|
||||
// Sensitive information should be included if the connection was
|
||||
// started by the current user OR the user is an admin
|
||||
boolean includeSensitiveInformation =
|
||||
// The current user should have access to sensitive information and
|
||||
// be able to connect to (join) the active connection if they are
|
||||
// the user that started the connection OR the user is an admin
|
||||
boolean hasPrivilegedAccess =
|
||||
isAdmin || username.equals(record.getUsername());
|
||||
|
||||
// Add connection if within requested identifiers
|
||||
if (identifierSet.contains(record.getUUID().toString())) {
|
||||
TrackedActiveConnection activeConnection = trackedActiveConnectionProvider.get();
|
||||
activeConnection.init(user, record, includeSensitiveInformation);
|
||||
activeConnection.init(user, record, hasPrivilegedAccess, hasPrivilegedAccess);
|
||||
activeConnections.add(activeConnection);
|
||||
}
|
||||
|
||||
|
@@ -21,15 +21,20 @@ package org.apache.guacamole.auth.jdbc.activeconnection;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
import org.apache.guacamole.GuacamoleSecurityException;
|
||||
import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
|
||||
import org.apache.guacamole.auth.jdbc.connection.ModeledConnection;
|
||||
import org.apache.guacamole.auth.jdbc.sharing.ConnectionSharingService;
|
||||
import org.apache.guacamole.auth.jdbc.sharing.connection.SharedConnectionDefinition;
|
||||
import org.apache.guacamole.auth.jdbc.tunnel.ActiveConnectionRecord;
|
||||
import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.net.GuacamoleTunnel;
|
||||
import org.apache.guacamole.net.auth.ActiveConnection;
|
||||
import org.apache.guacamole.net.auth.credentials.UserCredentials;
|
||||
import org.apache.guacamole.protocol.GuacamoleClientInformation;
|
||||
|
||||
/**
|
||||
* An implementation of the ActiveConnection object which has an associated
|
||||
@@ -43,6 +48,12 @@ public class TrackedActiveConnection extends RestrictedObject implements ActiveC
|
||||
@Inject
|
||||
private ConnectionSharingService sharingService;
|
||||
|
||||
/**
|
||||
* Service for creating and tracking tunnels.
|
||||
*/
|
||||
@Inject
|
||||
private GuacamoleTunnelService tunnelService;
|
||||
|
||||
/**
|
||||
* The identifier of this active connection.
|
||||
*/
|
||||
@@ -84,6 +95,11 @@ public class TrackedActiveConnection extends RestrictedObject implements ActiveC
|
||||
*/
|
||||
private GuacamoleTunnel tunnel;
|
||||
|
||||
/**
|
||||
* Whether connections to this TrackedActiveConnection are allowed.
|
||||
*/
|
||||
private boolean connectable;
|
||||
|
||||
/**
|
||||
* Initializes this TrackedActiveConnection, copying the data associated
|
||||
* with the given active connection record. At a minimum, the identifier
|
||||
@@ -102,13 +118,19 @@ public class TrackedActiveConnection extends RestrictedObject implements ActiveC
|
||||
* Whether sensitive data should be copied from the connection record
|
||||
* as well. This includes the remote host, associated tunnel, and
|
||||
* username.
|
||||
*
|
||||
* @param connectable
|
||||
* Whether the user that retrieved this object should be allowed to
|
||||
* join the active connection.
|
||||
*/
|
||||
public void init(ModeledAuthenticatedUser currentUser,
|
||||
ActiveConnectionRecord activeConnectionRecord,
|
||||
boolean includeSensitiveInformation) {
|
||||
boolean includeSensitiveInformation,
|
||||
boolean connectable) {
|
||||
|
||||
super.init(currentUser);
|
||||
this.connectionRecord = activeConnectionRecord;
|
||||
this.connectable = connectable;
|
||||
|
||||
// Copy all non-sensitive data from given record
|
||||
this.connection = activeConnectionRecord.getConnection();
|
||||
@@ -169,11 +191,32 @@ public class TrackedActiveConnection extends RestrictedObject implements ActiveC
|
||||
this.sharingProfileIdentifier = sharingProfileIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shares this active connection with the user that retrieved it, returning
|
||||
* a SharedConnectionDefinition that can be used to establish a tunnel to
|
||||
* the shared connection. If provided, access within the shared connection
|
||||
* will be restricted by the sharing profile with the given identifier.
|
||||
*
|
||||
* @param identifier
|
||||
* The identifier of the sharing profile that defines the restrictions
|
||||
* applying to the shared connection, or null if no such restrictions
|
||||
* apply.
|
||||
*
|
||||
* @return
|
||||
* A new SharedConnectionDefinition which can be used to establish a
|
||||
* tunnel to the shared connection.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If permission to share this active connection is denied.
|
||||
*/
|
||||
private SharedConnectionDefinition share(String identifier) throws GuacamoleException {
|
||||
return sharingService.shareConnection(getCurrentUser(), connectionRecord, identifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserCredentials getSharingCredentials(String identifier)
|
||||
throws GuacamoleException {
|
||||
return sharingService.generateTemporaryCredentials(getCurrentUser(),
|
||||
connectionRecord, identifier);
|
||||
return sharingService.getSharingCredentials(share(identifier));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -216,4 +259,26 @@ public class TrackedActiveConnection extends RestrictedObject implements ActiveC
|
||||
this.tunnel = tunnel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnectable() {
|
||||
return connectable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GuacamoleTunnel connect(GuacamoleClientInformation info,
|
||||
Map<String, String> tokens) throws GuacamoleException {
|
||||
|
||||
// Establish connection only if connecting is allowed
|
||||
if (isConnectable())
|
||||
return tunnelService.getGuacamoleTunnel(getCurrentUser(), share(null), info, tokens);
|
||||
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getActiveConnections() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@ package org.apache.guacamole.auth.jdbc.sharing;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
|
||||
import org.apache.guacamole.GuacamoleException;
|
||||
@@ -30,11 +31,14 @@ import org.apache.guacamole.auth.jdbc.sharing.user.SharedAuthenticatedUser;
|
||||
import org.apache.guacamole.auth.jdbc.sharingprofile.ModeledSharingProfile;
|
||||
import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileService;
|
||||
import org.apache.guacamole.auth.jdbc.tunnel.ActiveConnectionRecord;
|
||||
import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
|
||||
import org.apache.guacamole.auth.jdbc.user.RemoteAuthenticatedUser;
|
||||
import org.apache.guacamole.form.Field;
|
||||
import org.apache.guacamole.net.auth.AuthenticationProvider;
|
||||
import org.apache.guacamole.net.auth.Credentials;
|
||||
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
|
||||
import org.apache.guacamole.net.auth.credentials.UserCredentials;
|
||||
import org.apache.guacamole.protocol.GuacamoleClientInformation;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for sharing active connections.
|
||||
@@ -75,10 +79,16 @@ public class ConnectionSharingService {
|
||||
));
|
||||
|
||||
/**
|
||||
* Generates a set of temporary credentials which can be used to connect to
|
||||
* the given connection using the given sharing profile. If the user does
|
||||
* not have permission to share the connection via the given sharing
|
||||
* profile, permission will be denied.
|
||||
* Creates a new SharedConnectionDefinition which can be used to connect to
|
||||
* the given connection, optionally restricting access to the shared
|
||||
* connection using the given sharing profile. If the user does not have
|
||||
* permission to share the connection via the given sharing profile,
|
||||
* permission will be denied.
|
||||
*
|
||||
* @see GuacamoleTunnelService#getGuacamoleTunnel(RemoteAuthenticatedUser,
|
||||
* SharedConnectionDefinition, GuacamoleClientInformation, Map)
|
||||
*
|
||||
* @see #getSharingCredentials(SharedConnectionDefinition)
|
||||
*
|
||||
* @param user
|
||||
* The user sharing the connection.
|
||||
@@ -88,23 +98,27 @@ public class ConnectionSharingService {
|
||||
*
|
||||
* @param sharingProfileIdentifier
|
||||
* The identifier of the sharing profile dictating the semantics or
|
||||
* restrictions applying to the shared session.
|
||||
* restrictions applying to the shared session, or null if no such
|
||||
* restrictions should apply.
|
||||
*
|
||||
* @return
|
||||
* A newly-generated set of temporary credentials which can be used to
|
||||
* connect to the given connection.
|
||||
* A new SharedConnectionDefinition which can be used to connect to the
|
||||
* given connection.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If permission to share the given connection is denied.
|
||||
*/
|
||||
public UserCredentials generateTemporaryCredentials(ModeledAuthenticatedUser user,
|
||||
public SharedConnectionDefinition shareConnection(ModeledAuthenticatedUser user,
|
||||
ActiveConnectionRecord activeConnection,
|
||||
String sharingProfileIdentifier) throws GuacamoleException {
|
||||
|
||||
// If a sharing profile is provided, verify that permission to use that
|
||||
// profile to share the given connection is actually granted
|
||||
ModeledSharingProfile sharingProfile = null;
|
||||
if (sharingProfileIdentifier != null) {
|
||||
|
||||
// Pull sharing profile (verifying access)
|
||||
ModeledSharingProfile sharingProfile =
|
||||
sharingProfileService.retrieveObject(user,
|
||||
sharingProfileIdentifier);
|
||||
sharingProfile = sharingProfileService.retrieveObject(user, sharingProfileIdentifier);
|
||||
|
||||
// Verify that this profile is indeed a sharing profile for the
|
||||
// requested connection
|
||||
@@ -112,18 +126,39 @@ public class ConnectionSharingService {
|
||||
if (sharingProfile == null || !sharingProfile.getPrimaryConnectionIdentifier().equals(connectionIdentifier))
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
||||
}
|
||||
|
||||
// Generate a share key for the requested connection
|
||||
String key = keyGenerator.getShareKey();
|
||||
connectionMap.add(new SharedConnectionDefinition(activeConnection,
|
||||
sharingProfile, key));
|
||||
SharedConnectionDefinition definition = new SharedConnectionDefinition(activeConnection, sharingProfile, key);
|
||||
connectionMap.add(definition);
|
||||
|
||||
// Ensure the share key is properly invalidated when the original
|
||||
// connection is closed
|
||||
activeConnection.registerShareKey(key);
|
||||
|
||||
return definition;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a set of temporary credentials which can be used to connect to
|
||||
* the given connection shared by the SharedConnectionDefinition.
|
||||
*
|
||||
* @param definition
|
||||
* The SharedConnectionDefinition which defines the connection being
|
||||
* shared and any applicable restrictions.
|
||||
*
|
||||
* @return
|
||||
* A newly-generated set of temporary credentials which can be used to
|
||||
* connect to the connection shared by the given
|
||||
* SharedConnectionDefinition.
|
||||
*/
|
||||
public UserCredentials getSharingCredentials(SharedConnectionDefinition definition) {
|
||||
|
||||
// Return credentials defining a single expected parameter
|
||||
return new UserCredentials(SHARE_KEY,
|
||||
Collections.singletonMap(SHARE_KEY_NAME, key));
|
||||
Collections.singletonMap(SHARE_KEY_NAME, definition.getShareKey()));
|
||||
|
||||
}
|
||||
|
||||
|
@@ -29,9 +29,11 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Defines the semantics/restrictions of a shared connection by associating an
|
||||
* active connection with a sharing profile. The sharing profile defines the
|
||||
* access provided to users of the shared active connection through its
|
||||
* connection parameters.
|
||||
* active connection with an optional sharing profile. The sharing profile, if
|
||||
* present, defines the access provided to users of the shared active
|
||||
* connection through its connection parameters. If no sharing profile is
|
||||
* present, the shared connection has the same level of access as the original
|
||||
* connection.
|
||||
*/
|
||||
public class SharedConnectionDefinition {
|
||||
|
||||
@@ -88,7 +90,8 @@ public class SharedConnectionDefinition {
|
||||
*
|
||||
* @param sharingProfile
|
||||
* A sharing profile whose associated parameters dictate the level of
|
||||
* access provided to the shared connection.
|
||||
* access provided to the shared connection, or null if the connection
|
||||
* should be given full access.
|
||||
*
|
||||
* @param shareKey
|
||||
* The unique key with which a user may access the shared connection.
|
||||
|
@@ -202,8 +202,10 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
|
||||
|
||||
/**
|
||||
* Returns a guacamole configuration containing the protocol and parameters
|
||||
* from the given connection. If tokens are used in the connection
|
||||
* parameter values, credentials from the given user will be substituted
|
||||
* 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
|
||||
@@ -213,19 +215,29 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
|
||||
* The connection whose protocol and parameters should be added to the
|
||||
* returned configuration.
|
||||
*
|
||||
* @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) {
|
||||
ModeledConnection connection, String connectionID) {
|
||||
|
||||
// Generate configuration from available data
|
||||
GuacamoleConfiguration config = new GuacamoleConfiguration();
|
||||
|
||||
// Set protocol from connection
|
||||
// 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());
|
||||
@@ -470,16 +482,17 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
|
||||
// Retrieve connection information associated with given connection record
|
||||
ModeledConnection connection = activeConnection.getConnection();
|
||||
|
||||
// Pull configuration directly from the connection if we are not
|
||||
// joining an active connection
|
||||
// Pull configuration directly from the connection, additionally
|
||||
// joining the existing active connection (without sharing profile
|
||||
// restrictions) if such a connection exists
|
||||
if (activeConnection.isPrimaryConnection()) {
|
||||
activeConnections.put(connection.getIdentifier(), activeConnection);
|
||||
activeConnectionGroups.put(connection.getParentIdentifier(), activeConnection);
|
||||
config = getGuacamoleConfiguration(activeConnection.getUser(), connection);
|
||||
config = getGuacamoleConfiguration(activeConnection.getUser(), connection, activeConnection.getConnectionID());
|
||||
}
|
||||
|
||||
// If we ARE joining an active connection, generate a configuration
|
||||
// which does so
|
||||
// If we ARE joining an active connection under the restrictions of
|
||||
// a sharing profile, generate a configuration which does so
|
||||
else {
|
||||
|
||||
// Verify that the connection ID is known
|
||||
|
@@ -32,7 +32,6 @@ import org.apache.guacamole.net.AbstractGuacamoleTunnel;
|
||||
import org.apache.guacamole.net.GuacamoleSocket;
|
||||
import org.apache.guacamole.net.GuacamoleTunnel;
|
||||
import org.apache.guacamole.net.auth.ConnectionRecord;
|
||||
import org.apache.guacamole.protocol.ConfiguredGuacamoleSocket;
|
||||
|
||||
|
||||
/**
|
||||
@@ -202,8 +201,8 @@ public class ActiveConnectionRecord implements ConnectionRecord {
|
||||
*
|
||||
* @param sharingProfile
|
||||
* The sharing profile that was used to share access to the given
|
||||
* connection. As a record created in this way always refers to a
|
||||
* shared connection, this value may NOT be null.
|
||||
* connection, or null if no sharing profile should be used (access to
|
||||
* the connection is unrestricted).
|
||||
*/
|
||||
public void init(RemoteAuthenticatedUser user,
|
||||
ActiveConnectionRecord activeConnection,
|
||||
|
Reference in New Issue
Block a user