mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-10-27 15:13:07 +00:00
Merge pull request #247 from glyptodon/concurrent-policy
GUAC-830: Generalize tunnel services
This commit is contained in:
@@ -90,7 +90,14 @@
|
|||||||
<artifactId>guice-multibindings</artifactId>
|
<artifactId>guice-multibindings</artifactId>
|
||||||
<version>3.0</version>
|
<version>3.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Guava - Utility Library -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.guava</groupId>
|
||||||
|
<artifactId>guava</artifactId>
|
||||||
|
<version>18.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -82,10 +82,9 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
|
|||||||
private final Environment environment;
|
private final Environment environment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The service class to use to provide GuacamoleSockets for each
|
* The service to use to provide GuacamoleTunnels for each connection.
|
||||||
* connection.
|
|
||||||
*/
|
*/
|
||||||
private final Class<? extends GuacamoleTunnelService> tunnelServiceClass;
|
private final GuacamoleTunnelService tunnelService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new JDBC authentication provider module that configures the
|
* Creates a new JDBC authentication provider module that configures the
|
||||||
@@ -95,13 +94,13 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
|
|||||||
* @param environment
|
* @param environment
|
||||||
* The environment to use to configure injected classes.
|
* The environment to use to configure injected classes.
|
||||||
*
|
*
|
||||||
* @param tunnelServiceClass
|
* @param tunnelService
|
||||||
* The socket service to use to provide sockets for connections.
|
* The tunnel service to use to provide tunnels sockets for connections.
|
||||||
*/
|
*/
|
||||||
public JDBCAuthenticationProviderModule(Environment environment,
|
public JDBCAuthenticationProviderModule(Environment environment,
|
||||||
Class<? extends GuacamoleTunnelService> tunnelServiceClass) {
|
GuacamoleTunnelService tunnelService) {
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
this.tunnelServiceClass = tunnelServiceClass;
|
this.tunnelService = tunnelService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -156,8 +155,8 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
|
|||||||
bind(UserPermissionService.class);
|
bind(UserPermissionService.class);
|
||||||
bind(UserService.class);
|
bind(UserService.class);
|
||||||
|
|
||||||
// Bind provided socket service
|
// Bind provided tunnel service
|
||||||
bind(GuacamoleTunnelService.class).to(tunnelServiceClass);
|
bind(GuacamoleTunnelService.class).toInstance(tunnelService);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,88 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2015 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.auth.jdbc.tunnel;
|
|
||||||
|
|
||||||
import com.google.inject.Singleton;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection;
|
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
|
||||||
import org.glyptodon.guacamole.GuacamoleResourceConflictException;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GuacamoleTunnelService implementation which allows only one user per
|
|
||||||
* connection at any time, but does not disallow concurrent use of connection
|
|
||||||
* groups. If a user attempts to use a connection group multiple times, they
|
|
||||||
* will receive different underlying connections each time until the group is
|
|
||||||
* exhausted.
|
|
||||||
*
|
|
||||||
* @author Michael Jumper
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class BalancedGuacamoleTunnelService
|
|
||||||
extends AbstractGuacamoleTunnelService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The set of all active connection identifiers.
|
|
||||||
*/
|
|
||||||
private final Set<String> activeConnections =
|
|
||||||
Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ModeledConnection acquire(AuthenticatedUser user,
|
|
||||||
List<ModeledConnection> connections) throws GuacamoleException {
|
|
||||||
|
|
||||||
// Return the first unused connection
|
|
||||||
for (ModeledConnection connection : connections) {
|
|
||||||
if (activeConnections.add(connection.getIdentifier()))
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Already in use
|
|
||||||
throw new GuacamoleResourceConflictException("Cannot connect. This connection is in use.");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void release(AuthenticatedUser user, ModeledConnection connection) {
|
|
||||||
activeConnections.remove(connection.getIdentifier());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void acquire(AuthenticatedUser user,
|
|
||||||
ModeledConnectionGroup connectionGroup) throws GuacamoleException {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void release(AuthenticatedUser user,
|
|
||||||
ModeledConnectionGroup connectionGroup) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,276 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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.auth.jdbc.tunnel;
|
||||||
|
|
||||||
|
import com.google.common.collect.ConcurrentHashMultiset;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
import org.glyptodon.guacamole.GuacamoleClientTooManyException;
|
||||||
|
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
|
||||||
|
import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection;
|
||||||
|
import org.glyptodon.guacamole.GuacamoleException;
|
||||||
|
import org.glyptodon.guacamole.GuacamoleResourceConflictException;
|
||||||
|
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GuacamoleTunnelService implementation which restricts concurrency for each
|
||||||
|
* connection and group according to a maximum number of connections and
|
||||||
|
* maximum number of connections per user.
|
||||||
|
*
|
||||||
|
* @author James Muehlner
|
||||||
|
* @author Michael Jumper
|
||||||
|
*/
|
||||||
|
@Singleton
|
||||||
|
public class ConfigurableGuacamoleTunnelService
|
||||||
|
extends AbstractGuacamoleTunnelService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of all currently-active user/connection pairs (seats).
|
||||||
|
*/
|
||||||
|
private final ConcurrentHashMultiset<Seat> activeSeats = ConcurrentHashMultiset.<Seat>create();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of all currently-active connections.
|
||||||
|
*/
|
||||||
|
private final ConcurrentHashMultiset<String> activeConnections = ConcurrentHashMultiset.<String>create();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of all currently-active user/connection group pairs (seats).
|
||||||
|
*/
|
||||||
|
private final ConcurrentHashMultiset<Seat> activeGroupSeats = ConcurrentHashMultiset.<Seat>create();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set of all currently-active connection groups.
|
||||||
|
*/
|
||||||
|
private final ConcurrentHashMultiset<String> activeGroups = ConcurrentHashMultiset.<String>create();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of connections allowed per connection by default, or
|
||||||
|
* zero if no default limit applies.
|
||||||
|
*/
|
||||||
|
private final int connectionDefaultMaxConnections;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of connections a user may have to any one connection
|
||||||
|
* by default, or zero if no default limit applies.
|
||||||
|
*/
|
||||||
|
private final int connectionDefaultMaxConnectionsPerUser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of connections allowed per connection group by
|
||||||
|
* default, or zero if no default limit applies.
|
||||||
|
*/
|
||||||
|
private final int connectionGroupDefaultMaxConnections;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of connections a user may have to any one connection
|
||||||
|
* group by default, or zero if no default limit applies.
|
||||||
|
*/
|
||||||
|
private final int connectionGroupDefaultMaxConnectionsPerUser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new ConfigurableGuacamoleTunnelService which applies the given
|
||||||
|
* limitations when new connections are acquired.
|
||||||
|
*
|
||||||
|
* @param connectionDefaultMaxConnections
|
||||||
|
* The maximum number of connections allowed per connection by default,
|
||||||
|
* or zero if no default limit applies.
|
||||||
|
*
|
||||||
|
* @param connectionDefaultMaxConnectionsPerUser
|
||||||
|
* The maximum number of connections a user may have to any one
|
||||||
|
* connection by default, or zero if no default limit applies.
|
||||||
|
*
|
||||||
|
* @param connectionGroupDefaultMaxConnections
|
||||||
|
* The maximum number of connections allowed per connection group by
|
||||||
|
* default, or zero if no default limit applies.
|
||||||
|
*
|
||||||
|
* @param connectionGroupDefaultMaxConnectionsPerUser
|
||||||
|
* The maximum number of connections a user may have to any one
|
||||||
|
* connection group by default, or zero if no default limit applies.
|
||||||
|
*/
|
||||||
|
public ConfigurableGuacamoleTunnelService(
|
||||||
|
int connectionDefaultMaxConnections,
|
||||||
|
int connectionDefaultMaxConnectionsPerUser,
|
||||||
|
int connectionGroupDefaultMaxConnections,
|
||||||
|
int connectionGroupDefaultMaxConnectionsPerUser) {
|
||||||
|
|
||||||
|
// Set default connection limits
|
||||||
|
this.connectionDefaultMaxConnections = connectionDefaultMaxConnections;
|
||||||
|
this.connectionDefaultMaxConnectionsPerUser = connectionDefaultMaxConnectionsPerUser;
|
||||||
|
|
||||||
|
// Set default connection group limits
|
||||||
|
this.connectionGroupDefaultMaxConnections = connectionGroupDefaultMaxConnections;
|
||||||
|
this.connectionGroupDefaultMaxConnectionsPerUser = connectionGroupDefaultMaxConnectionsPerUser;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to add a single instance of the given value to the given
|
||||||
|
* multiset without exceeding the specified maximum number of values. If
|
||||||
|
* the value cannot be added without exceeding the maximum, false is
|
||||||
|
* returned.
|
||||||
|
*
|
||||||
|
* @param <T>
|
||||||
|
* The type of values contained within the multiset.
|
||||||
|
*
|
||||||
|
* @param multiset
|
||||||
|
* The multiset to attempt to add a value to.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* The value to attempt to add.
|
||||||
|
*
|
||||||
|
* @param max
|
||||||
|
* The maximum number of each distinct value that the given multiset
|
||||||
|
* should hold, or zero if no limit applies.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* true if the value was successfully added without exceeding the
|
||||||
|
* specified maximum, false if the value could not be added.
|
||||||
|
*/
|
||||||
|
private <T> boolean tryAdd(ConcurrentHashMultiset<T> multiset, T value, int max) {
|
||||||
|
|
||||||
|
// Repeatedly attempt to add a new value to the given multiset until we
|
||||||
|
// explicitly succeed or explicitly fail
|
||||||
|
while (true) {
|
||||||
|
|
||||||
|
// Get current number of values
|
||||||
|
int count = multiset.count(value);
|
||||||
|
|
||||||
|
// Bail out if the maximum has already been reached
|
||||||
|
if (count >= max || max == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Attempt to add one more value
|
||||||
|
if (multiset.setCount(value, count, count+1))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Try again if unsuccessful
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ModeledConnection acquire(AuthenticatedUser user,
|
||||||
|
List<ModeledConnection> connections) throws GuacamoleException {
|
||||||
|
|
||||||
|
// Get username
|
||||||
|
String username = user.getUser().getIdentifier();
|
||||||
|
|
||||||
|
// Sort connections in ascending order of usage
|
||||||
|
ModeledConnection[] sortedConnections = connections.toArray(new ModeledConnection[connections.size()]);
|
||||||
|
Arrays.sort(sortedConnections, new Comparator<ModeledConnection>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compare(ModeledConnection a, ModeledConnection b) {
|
||||||
|
|
||||||
|
return getActiveConnections(a).size()
|
||||||
|
- getActiveConnections(b).size();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
// Track whether acquire fails due to user-specific limits
|
||||||
|
boolean userSpecificFailure = true;
|
||||||
|
|
||||||
|
// Return the first unreserved connection
|
||||||
|
for (ModeledConnection connection : sortedConnections) {
|
||||||
|
|
||||||
|
// Attempt to aquire connection according to per-user limits
|
||||||
|
Seat seat = new Seat(username, connection.getIdentifier());
|
||||||
|
if (tryAdd(activeSeats, seat,
|
||||||
|
connectionDefaultMaxConnectionsPerUser)) {
|
||||||
|
|
||||||
|
// Attempt to aquire connection according to overall limits
|
||||||
|
if (tryAdd(activeConnections, connection.getIdentifier(),
|
||||||
|
connectionDefaultMaxConnections))
|
||||||
|
return connection;
|
||||||
|
|
||||||
|
// Acquire failed - retry with next connection
|
||||||
|
activeSeats.remove(seat);
|
||||||
|
|
||||||
|
// Failure to acquire is not user-specific
|
||||||
|
userSpecificFailure = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Too many connections by this user
|
||||||
|
if (userSpecificFailure)
|
||||||
|
throw new GuacamoleClientTooManyException("Cannot connect. Connection group already in use by this user.");
|
||||||
|
|
||||||
|
// Too many connections, but not necessarily due purely to this user
|
||||||
|
else
|
||||||
|
throw new GuacamoleResourceConflictException("Cannot connect. This connection is in use.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void release(AuthenticatedUser user, ModeledConnection connection) {
|
||||||
|
activeSeats.remove(new Seat(user.getUser().getIdentifier(), connection.getIdentifier()));
|
||||||
|
activeConnections.remove(connection.getIdentifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void acquire(AuthenticatedUser user,
|
||||||
|
ModeledConnectionGroup connectionGroup) throws GuacamoleException {
|
||||||
|
|
||||||
|
// Get username
|
||||||
|
String username = user.getUser().getIdentifier();
|
||||||
|
|
||||||
|
// Attempt to aquire connection group according to per-user limits
|
||||||
|
Seat seat = new Seat(username, connectionGroup.getIdentifier());
|
||||||
|
if (tryAdd(activeGroupSeats, seat,
|
||||||
|
connectionGroupDefaultMaxConnectionsPerUser)) {
|
||||||
|
|
||||||
|
// Attempt to aquire connection group according to overall limits
|
||||||
|
if (tryAdd(activeGroups, connectionGroup.getIdentifier(),
|
||||||
|
connectionGroupDefaultMaxConnections))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Acquire failed
|
||||||
|
activeGroupSeats.remove(seat);
|
||||||
|
|
||||||
|
// Failure to acquire is not user-specific
|
||||||
|
throw new GuacamoleResourceConflictException("Cannot connect. This connection group is in use.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Already in use by this user
|
||||||
|
throw new GuacamoleClientTooManyException("Cannot connect. Connection group already in use by this user.");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void release(AuthenticatedUser user,
|
||||||
|
ModeledConnectionGroup connectionGroup) {
|
||||||
|
activeGroupSeats.remove(new Seat(user.getUser().getIdentifier(), connectionGroup.getIdentifier()));
|
||||||
|
activeGroups.remove(connectionGroup.getIdentifier());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2015 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.auth.jdbc.tunnel;
|
|
||||||
|
|
||||||
import com.google.inject.Singleton;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import org.glyptodon.guacamole.GuacamoleClientTooManyException;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection;
|
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
|
||||||
import org.glyptodon.guacamole.GuacamoleResourceConflictException;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GuacamoleTunnelService implementation which restricts concurrency only on a
|
|
||||||
* per-user basis. Each connection or group may be used concurrently any number
|
|
||||||
* of times, but each concurrent use must be associated with a different user.
|
|
||||||
*
|
|
||||||
* @author Michael Jumper
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class MultiseatGuacamoleTunnelService
|
|
||||||
extends AbstractGuacamoleTunnelService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The set of all active user/connection pairs.
|
|
||||||
*/
|
|
||||||
private final Set<Seat> activeSeats =
|
|
||||||
Collections.newSetFromMap(new ConcurrentHashMap<Seat, Boolean>());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The set of all active user/connection group pairs.
|
|
||||||
*/
|
|
||||||
private final Set<Seat> activeGroupSeats =
|
|
||||||
Collections.newSetFromMap(new ConcurrentHashMap<Seat, Boolean>());
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ModeledConnection acquire(AuthenticatedUser user,
|
|
||||||
List<ModeledConnection> connections) throws GuacamoleException {
|
|
||||||
|
|
||||||
String username = user.getUser().getIdentifier();
|
|
||||||
|
|
||||||
// Sort connections in ascending order of usage
|
|
||||||
ModeledConnection[] sortedConnections = connections.toArray(new ModeledConnection[connections.size()]);
|
|
||||||
Arrays.sort(sortedConnections, new Comparator<ModeledConnection>() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int compare(ModeledConnection a, ModeledConnection b) {
|
|
||||||
|
|
||||||
return getActiveConnections(a).size()
|
|
||||||
- getActiveConnections(b).size();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// Return the first unreserved connection
|
|
||||||
for (ModeledConnection connection : sortedConnections) {
|
|
||||||
if (activeSeats.add(new Seat(username, connection.getIdentifier())))
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Already in use
|
|
||||||
throw new GuacamoleResourceConflictException("Cannot connect. This connection is in use.");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void release(AuthenticatedUser user, ModeledConnection connection) {
|
|
||||||
activeSeats.remove(new Seat(user.getUser().getIdentifier(), connection.getIdentifier()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void acquire(AuthenticatedUser user,
|
|
||||||
ModeledConnectionGroup connectionGroup) throws GuacamoleException {
|
|
||||||
|
|
||||||
// Do not allow duplicate use of connection groups
|
|
||||||
Seat seat = new Seat(user.getUser().getIdentifier(), connectionGroup.getIdentifier());
|
|
||||||
if (!activeGroupSeats.add(seat))
|
|
||||||
throw new GuacamoleClientTooManyException("Cannot connect. Connection group already in use by this user.");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void release(AuthenticatedUser user,
|
|
||||||
ModeledConnectionGroup connectionGroup) {
|
|
||||||
activeGroupSeats.remove(new Seat(user.getUser().getIdentifier(), connectionGroup.getIdentifier()));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2015 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.auth.jdbc.tunnel;
|
|
||||||
|
|
||||||
import com.google.inject.Singleton;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import org.glyptodon.guacamole.GuacamoleClientTooManyException;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection;
|
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
|
||||||
import org.glyptodon.guacamole.GuacamoleResourceConflictException;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GuacamoleTunnelService implementation which allows exactly one use
|
|
||||||
* of any connection at any time. Concurrent usage of connections is not
|
|
||||||
* allowed, and concurrent usage of connection groups is allowed only between
|
|
||||||
* different users.
|
|
||||||
*
|
|
||||||
* @author Michael Jumper
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class SingleSeatGuacamoleTunnelService
|
|
||||||
extends AbstractGuacamoleTunnelService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The set of all active connection identifiers.
|
|
||||||
*/
|
|
||||||
private final Set<String> activeConnections =
|
|
||||||
Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The set of all active user/connection group pairs.
|
|
||||||
*/
|
|
||||||
private final Set<Seat> activeGroupSeats =
|
|
||||||
Collections.newSetFromMap(new ConcurrentHashMap<Seat, Boolean>());
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ModeledConnection acquire(AuthenticatedUser user,
|
|
||||||
List<ModeledConnection> connections) throws GuacamoleException {
|
|
||||||
|
|
||||||
// Return the first unused connection
|
|
||||||
for (ModeledConnection connection : connections) {
|
|
||||||
if (activeConnections.add(connection.getIdentifier()))
|
|
||||||
return connection;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Already in use
|
|
||||||
throw new GuacamoleResourceConflictException("Cannot connect. This connection is in use.");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void release(AuthenticatedUser user, ModeledConnection connection) {
|
|
||||||
activeConnections.remove(connection.getIdentifier());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void acquire(AuthenticatedUser user,
|
|
||||||
ModeledConnectionGroup connectionGroup) throws GuacamoleException {
|
|
||||||
|
|
||||||
// Do not allow duplicate use of connection groups
|
|
||||||
Seat seat = new Seat(user.getUser().getIdentifier(), connectionGroup.getIdentifier());
|
|
||||||
if (!activeGroupSeats.add(seat))
|
|
||||||
throw new GuacamoleClientTooManyException("Cannot connect. Connection group already in use by this user.");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void release(AuthenticatedUser user,
|
|
||||||
ModeledConnectionGroup connectionGroup) {
|
|
||||||
activeGroupSeats.remove(new Seat(user.getUser().getIdentifier(), connectionGroup.getIdentifier()));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (C) 2015 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.auth.jdbc.tunnel;
|
|
||||||
|
|
||||||
import com.google.inject.Singleton;
|
|
||||||
import java.util.List;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection;
|
|
||||||
import org.glyptodon.guacamole.GuacamoleException;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GuacamoleTunnelService implementation which imposes no restrictions
|
|
||||||
* whatsoever on the number of concurrent or duplicate connections.
|
|
||||||
*
|
|
||||||
* @author Michael Jumper
|
|
||||||
*/
|
|
||||||
@Singleton
|
|
||||||
public class UnrestrictedGuacamoleTunnelService
|
|
||||||
extends AbstractGuacamoleTunnelService {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ModeledConnection acquire(AuthenticatedUser user,
|
|
||||||
List<ModeledConnection> connections) throws GuacamoleException {
|
|
||||||
|
|
||||||
ModeledConnection chosen = null;
|
|
||||||
int lowestUsage = 0;
|
|
||||||
|
|
||||||
// Find connection with lowest usage
|
|
||||||
for (ModeledConnection connection : connections) {
|
|
||||||
|
|
||||||
int usage = getActiveConnections(connection).size();
|
|
||||||
if (chosen == null || usage < lowestUsage) {
|
|
||||||
chosen = connection;
|
|
||||||
lowestUsage = usage;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return chosen;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void release(AuthenticatedUser user, ModeledConnection connection) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void acquire(AuthenticatedUser user,
|
|
||||||
ModeledConnectionGroup connectionGroup) throws GuacamoleException {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void release(AuthenticatedUser user,
|
|
||||||
ModeledConnectionGroup connectionGroup) {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -30,10 +30,7 @@ import org.glyptodon.guacamole.net.auth.Credentials;
|
|||||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||||
import org.glyptodon.guacamole.auth.jdbc.JDBCAuthenticationProviderModule;
|
import org.glyptodon.guacamole.auth.jdbc.JDBCAuthenticationProviderModule;
|
||||||
import org.glyptodon.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
|
import org.glyptodon.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
|
||||||
import org.glyptodon.guacamole.auth.jdbc.tunnel.MultiseatGuacamoleTunnelService;
|
import org.glyptodon.guacamole.auth.jdbc.tunnel.ConfigurableGuacamoleTunnelService;
|
||||||
import org.glyptodon.guacamole.auth.jdbc.tunnel.BalancedGuacamoleTunnelService;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.tunnel.SingleSeatGuacamoleTunnelService;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.tunnel.UnrestrictedGuacamoleTunnelService;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.user.UserContextService;
|
import org.glyptodon.guacamole.auth.jdbc.user.UserContextService;
|
||||||
import org.glyptodon.guacamole.environment.Environment;
|
import org.glyptodon.guacamole.environment.Environment;
|
||||||
import org.glyptodon.guacamole.environment.LocalEnvironment;
|
import org.glyptodon.guacamole.environment.LocalEnvironment;
|
||||||
@@ -54,52 +51,62 @@ public class MySQLAuthenticationProvider implements AuthenticationProvider {
|
|||||||
private final Injector injector;
|
private final Injector injector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the appropriate socket service class given the Guacamole
|
* Returns the appropriate tunnel service given the Guacamole environment.
|
||||||
* environment. The class is chosen based on configuration options that
|
* The service is configured based on configuration options that dictate
|
||||||
* dictate concurrent usage policy.
|
* the default concurrent usage policy.
|
||||||
*
|
*
|
||||||
* @param environment
|
* @param environment
|
||||||
* The environment of the Guacamole server.
|
* The environment of the Guacamole server.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* The socket service class that matches the concurrent usage policy
|
* A tunnel service implementation configured according to the
|
||||||
* options set in the Guacamole environment.
|
* concurrent usage policy options set in the Guacamole environment.
|
||||||
*
|
*
|
||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If an error occurs while reading the configuration options.
|
* If an error occurs while reading the configuration options.
|
||||||
*/
|
*/
|
||||||
private Class<? extends GuacamoleTunnelService>
|
private GuacamoleTunnelService getTunnelService(Environment environment)
|
||||||
getSocketServiceClass(Environment environment)
|
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Read concurrency-related properties
|
// Tunnel service default configuration
|
||||||
|
int connectionDefaultMaxConnections;
|
||||||
|
int connectionDefaultMaxConnectionsPerUser;
|
||||||
|
int connectionGroupDefaultMaxConnections;
|
||||||
|
int connectionGroupDefaultMaxConnectionsPerUser;
|
||||||
|
|
||||||
|
// Read legacy concurrency-related properties
|
||||||
boolean disallowSimultaneous = environment.getProperty(MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS, false);
|
boolean disallowSimultaneous = environment.getProperty(MySQLGuacamoleProperties.MYSQL_DISALLOW_SIMULTANEOUS_CONNECTIONS, false);
|
||||||
boolean disallowDuplicate = environment.getProperty(MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS, true);
|
boolean disallowDuplicate = environment.getProperty(MySQLGuacamoleProperties.MYSQL_DISALLOW_DUPLICATE_CONNECTIONS, true);
|
||||||
|
|
||||||
if (disallowSimultaneous) {
|
// Legacy properties to not affect max connections per group
|
||||||
|
connectionGroupDefaultMaxConnections = 0;
|
||||||
|
|
||||||
// Connections may not be used concurrently
|
// Legacy "simultaneous" property dictates only the maximum number of
|
||||||
if (disallowDuplicate)
|
// connections per connection
|
||||||
return SingleSeatGuacamoleTunnelService.class;
|
if (disallowSimultaneous)
|
||||||
|
connectionDefaultMaxConnections = 1;
|
||||||
// Connections are reserved for a single user when in use
|
else
|
||||||
else
|
connectionDefaultMaxConnections = 0;
|
||||||
return BalancedGuacamoleTunnelService.class;
|
|
||||||
|
|
||||||
|
// Legacy "duplicate" property dictates whether connections and groups
|
||||||
|
// may be used concurrently only by different users
|
||||||
|
if (disallowDuplicate) {
|
||||||
|
connectionDefaultMaxConnectionsPerUser = 1;
|
||||||
|
connectionGroupDefaultMaxConnectionsPerUser = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
|
connectionDefaultMaxConnectionsPerUser = 0;
|
||||||
// Connections may be used concurrently, but only once per user
|
connectionGroupDefaultMaxConnectionsPerUser = 0;
|
||||||
if (disallowDuplicate)
|
|
||||||
return MultiseatGuacamoleTunnelService.class;
|
|
||||||
|
|
||||||
// Connection use is not restricted
|
|
||||||
else
|
|
||||||
return UnrestrictedGuacamoleTunnelService.class;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return service configured for specified default limits
|
||||||
|
return new ConfigurableGuacamoleTunnelService(
|
||||||
|
connectionDefaultMaxConnections,
|
||||||
|
connectionDefaultMaxConnectionsPerUser,
|
||||||
|
connectionGroupDefaultMaxConnections,
|
||||||
|
connectionGroupDefaultMaxConnectionsPerUser
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -123,7 +130,7 @@ public class MySQLAuthenticationProvider implements AuthenticationProvider {
|
|||||||
new MySQLAuthenticationProviderModule(environment),
|
new MySQLAuthenticationProviderModule(environment),
|
||||||
|
|
||||||
// Configure JDBC authentication core
|
// Configure JDBC authentication core
|
||||||
new JDBCAuthenticationProviderModule(environment, getSocketServiceClass(environment))
|
new JDBCAuthenticationProviderModule(environment, getTunnelService(environment))
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -29,11 +29,8 @@ import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
|
|||||||
import org.glyptodon.guacamole.net.auth.Credentials;
|
import org.glyptodon.guacamole.net.auth.Credentials;
|
||||||
import org.glyptodon.guacamole.net.auth.UserContext;
|
import org.glyptodon.guacamole.net.auth.UserContext;
|
||||||
import org.glyptodon.guacamole.auth.jdbc.JDBCAuthenticationProviderModule;
|
import org.glyptodon.guacamole.auth.jdbc.JDBCAuthenticationProviderModule;
|
||||||
import org.glyptodon.guacamole.auth.jdbc.tunnel.BalancedGuacamoleTunnelService;
|
import org.glyptodon.guacamole.auth.jdbc.tunnel.ConfigurableGuacamoleTunnelService;
|
||||||
import org.glyptodon.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
|
import org.glyptodon.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
|
||||||
import org.glyptodon.guacamole.auth.jdbc.tunnel.MultiseatGuacamoleTunnelService;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.tunnel.SingleSeatGuacamoleTunnelService;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.tunnel.UnrestrictedGuacamoleTunnelService;
|
|
||||||
import org.glyptodon.guacamole.auth.jdbc.user.UserContextService;
|
import org.glyptodon.guacamole.auth.jdbc.user.UserContextService;
|
||||||
import org.glyptodon.guacamole.environment.Environment;
|
import org.glyptodon.guacamole.environment.Environment;
|
||||||
import org.glyptodon.guacamole.environment.LocalEnvironment;
|
import org.glyptodon.guacamole.environment.LocalEnvironment;
|
||||||
@@ -54,52 +51,62 @@ public class PostgreSQLAuthenticationProvider implements AuthenticationProvider
|
|||||||
private final Injector injector;
|
private final Injector injector;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the appropriate socket service class given the Guacamole
|
* Returns the appropriate tunnel service given the Guacamole environment.
|
||||||
* environment. The class is chosen based on configuration options that
|
* The service is configured based on configuration options that dictate
|
||||||
* dictate concurrent usage policy.
|
* the default concurrent usage policy.
|
||||||
*
|
*
|
||||||
* @param environment
|
* @param environment
|
||||||
* The environment of the Guacamole server.
|
* The environment of the Guacamole server.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* The socket service class that matches the concurrent usage policy
|
* A tunnel service implementation configured according to the
|
||||||
* options set in the Guacamole environment.
|
* concurrent usage policy options set in the Guacamole environment.
|
||||||
*
|
*
|
||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If an error occurs while reading the configuration options.
|
* If an error occurs while reading the configuration options.
|
||||||
*/
|
*/
|
||||||
private Class<? extends GuacamoleTunnelService>
|
private GuacamoleTunnelService getTunnelService(Environment environment)
|
||||||
getSocketServiceClass(Environment environment)
|
|
||||||
throws GuacamoleException {
|
throws GuacamoleException {
|
||||||
|
|
||||||
// Read concurrency-related properties
|
// Tunnel service default configuration
|
||||||
|
int connectionDefaultMaxConnections;
|
||||||
|
int connectionDefaultMaxConnectionsPerUser;
|
||||||
|
int connectionGroupDefaultMaxConnections;
|
||||||
|
int connectionGroupDefaultMaxConnectionsPerUser;
|
||||||
|
|
||||||
|
// Read legacy concurrency-related properties
|
||||||
boolean disallowSimultaneous = environment.getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_DISALLOW_SIMULTANEOUS_CONNECTIONS, false);
|
boolean disallowSimultaneous = environment.getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_DISALLOW_SIMULTANEOUS_CONNECTIONS, false);
|
||||||
boolean disallowDuplicate = environment.getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_DISALLOW_DUPLICATE_CONNECTIONS, true);
|
boolean disallowDuplicate = environment.getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_DISALLOW_DUPLICATE_CONNECTIONS, true);
|
||||||
|
|
||||||
if (disallowSimultaneous) {
|
// Legacy properties to not affect max connections per group
|
||||||
|
connectionGroupDefaultMaxConnections = 0;
|
||||||
|
|
||||||
// Connections may not be used concurrently
|
// Legacy "simultaneous" property dictates only the maximum number of
|
||||||
if (disallowDuplicate)
|
// connections per connection
|
||||||
return SingleSeatGuacamoleTunnelService.class;
|
if (disallowSimultaneous)
|
||||||
|
connectionDefaultMaxConnections = 1;
|
||||||
// Connections are reserved for a single user when in use
|
else
|
||||||
else
|
connectionDefaultMaxConnections = 0;
|
||||||
return BalancedGuacamoleTunnelService.class;
|
|
||||||
|
|
||||||
|
// Legacy "duplicate" property dictates whether connections and groups
|
||||||
|
// may be used concurrently only by different users
|
||||||
|
if (disallowDuplicate) {
|
||||||
|
connectionDefaultMaxConnectionsPerUser = 1;
|
||||||
|
connectionGroupDefaultMaxConnectionsPerUser = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
|
connectionDefaultMaxConnectionsPerUser = 0;
|
||||||
// Connections may be used concurrently, but only once per user
|
connectionGroupDefaultMaxConnectionsPerUser = 0;
|
||||||
if (disallowDuplicate)
|
|
||||||
return MultiseatGuacamoleTunnelService.class;
|
|
||||||
|
|
||||||
// Connection use is not restricted
|
|
||||||
else
|
|
||||||
return UnrestrictedGuacamoleTunnelService.class;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return service configured for specified default limits
|
||||||
|
return new ConfigurableGuacamoleTunnelService(
|
||||||
|
connectionDefaultMaxConnections,
|
||||||
|
connectionDefaultMaxConnectionsPerUser,
|
||||||
|
connectionGroupDefaultMaxConnections,
|
||||||
|
connectionGroupDefaultMaxConnectionsPerUser
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -123,7 +130,7 @@ public class PostgreSQLAuthenticationProvider implements AuthenticationProvider
|
|||||||
new PostgreSQLAuthenticationProviderModule(environment),
|
new PostgreSQLAuthenticationProviderModule(environment),
|
||||||
|
|
||||||
// Configure JDBC authentication core
|
// Configure JDBC authentication core
|
||||||
new JDBCAuthenticationProviderModule(environment, getSocketServiceClass(environment))
|
new JDBCAuthenticationProviderModule(environment, getTunnelService(environment))
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user