mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
GUAC-1101: Move connection logic into GuacamoleSocketService, with policy-specific implementations.
This commit is contained in:
@@ -39,11 +39,13 @@ import org.glyptodon.guacamole.net.auth.UserContext;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.dao.UserMapper;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.properties.MySQLGuacamoleProperties;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionService;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.service.GuacamoleSocketService;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.service.PasswordEncryptionService;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.service.SHA256PasswordEncryptionService;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.service.SaltService;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.service.SecureRandomSaltService;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.service.SystemPermissionService;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.service.UnrestrictedGuacamoleSocketService;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.service.UserService;
|
||||
import org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory;
|
||||
import org.glyptodon.guacamole.environment.Environment;
|
||||
@@ -164,6 +166,9 @@ public class MySQLAuthenticationProvider implements AuthenticationProvider {
|
||||
bind(SystemPermissionService.class);
|
||||
bind(UserService.class);
|
||||
|
||||
// Bind appropriate socket service based on policy
|
||||
bind(GuacamoleSocketService.class).to(UnrestrictedGuacamoleSocketService.class);
|
||||
|
||||
}
|
||||
} // end of mybatis module
|
||||
|
||||
|
@@ -28,6 +28,7 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionModel;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionService;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.service.GuacamoleSocketService;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.GuacamoleSocket;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
@@ -59,6 +60,12 @@ public class MySQLConnection implements Connection, DirectoryObject<ConnectionMo
|
||||
@Inject
|
||||
private ConnectionService connectionService;
|
||||
|
||||
/**
|
||||
* Service for creating and tracking sockets.
|
||||
*/
|
||||
@Inject
|
||||
private GuacamoleSocketService socketService;
|
||||
|
||||
/**
|
||||
* Provider for lazy-loaded, permission-controlled configurations.
|
||||
*/
|
||||
@@ -185,8 +192,7 @@ public class MySQLConnection implements Connection, DirectoryObject<ConnectionMo
|
||||
|
||||
@Override
|
||||
public int getActiveConnections() {
|
||||
/* STUB */
|
||||
return 0;
|
||||
return socketService.getActiveConnections(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
* 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 net.sourceforge.guacamole.net.auth.mysql.service;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.AuthenticatedUser;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.MySQLConnection;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.dao.ParameterMapper;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionModel;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.model.ParameterModel;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.environment.Environment;
|
||||
import org.glyptodon.guacamole.net.GuacamoleSocket;
|
||||
import org.glyptodon.guacamole.net.InetGuacamoleSocket;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
import org.glyptodon.guacamole.protocol.ConfiguredGuacamoleSocket;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
|
||||
|
||||
|
||||
/**
|
||||
* Base implementation of the GuacamoleSocketService, handling retrieval of
|
||||
* connection parameters, load balancing, and connection usage counts. The
|
||||
* implementation of concurrency rules is up to policy-specific subclasses.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketService {
|
||||
|
||||
/**
|
||||
* The environment of the Guacamole server.
|
||||
*/
|
||||
@Inject
|
||||
private Environment environment;
|
||||
|
||||
/**
|
||||
* Mapper for accessing connection parameters.
|
||||
*/
|
||||
@Inject
|
||||
private ParameterMapper parameterMapper;
|
||||
|
||||
/**
|
||||
* The current number of concurrent uses of the connection having a given
|
||||
* identifier.
|
||||
*/
|
||||
private final ConcurrentHashMap<String, AtomicInteger> activeConnectionCount =
|
||||
new ConcurrentHashMap<String, AtomicInteger>();
|
||||
|
||||
/**
|
||||
* Atomically increments the current usage count for the given connection.
|
||||
*
|
||||
* @param connection
|
||||
* The connection which is being used.
|
||||
*/
|
||||
private void incrementUsage(MySQLConnection connection) {
|
||||
|
||||
// Increment or initialize usage count atomically
|
||||
AtomicInteger count = activeConnectionCount.putIfAbsent(connection.getIdentifier(), new AtomicInteger(1));
|
||||
if (count != null)
|
||||
count.incrementAndGet();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Atomically decrements the current usage count for the given connection.
|
||||
* If a combination of incrementUsage() and decrementUsage() calls result
|
||||
* in the usage counter being reduced to zero, it is guaranteed that one
|
||||
* of those decrementUsage() calls will remove the value from the map.
|
||||
*
|
||||
* @param connection
|
||||
* The connection which is no longer being used.
|
||||
*/
|
||||
private void decrementUsage(MySQLConnection connection) {
|
||||
|
||||
// Decrement usage count, remove entry if it becomes zero
|
||||
AtomicInteger count = activeConnectionCount.get(connection.getIdentifier());
|
||||
if (count != null) {
|
||||
count.decrementAndGet();
|
||||
activeConnectionCount.remove(connection.getIdentifier(), 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquires possibly-exclusive access to the given connection on behalf of
|
||||
* the given user. If access is denied for any reason, an exception is
|
||||
* thrown.
|
||||
*
|
||||
* @param user
|
||||
* The user acquiring access.
|
||||
*
|
||||
* @param connection
|
||||
* The connection being accessed.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If access is denied to the given user for any reason.
|
||||
*/
|
||||
protected abstract void acquire(AuthenticatedUser user,
|
||||
MySQLConnection connection) throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Releases possibly-exclusive access to the given connection on behalf of
|
||||
* the given user. If the given user did not already have access, the
|
||||
* behavior of this function is undefined.
|
||||
*
|
||||
* @param user
|
||||
* The user releasing access.
|
||||
*
|
||||
* @param connection
|
||||
* The connection being released.
|
||||
*/
|
||||
protected abstract void release(AuthenticatedUser user,
|
||||
MySQLConnection connection);
|
||||
|
||||
/**
|
||||
* Creates a socket for the given user which connects to the given
|
||||
* connection. The given client information will be passed to guacd when
|
||||
* the connection is established. This function will apply any concurrent
|
||||
* usage rules in effect, but will NOT test object- or system-level
|
||||
* permissions.
|
||||
*
|
||||
* @param user
|
||||
* The user for whom the connection is being established.
|
||||
*
|
||||
* @param connection
|
||||
* The connection the user is connecting to.
|
||||
*
|
||||
* @param info
|
||||
* Information describing the Guacamole client connecting to the given
|
||||
* connection.
|
||||
*
|
||||
* @return
|
||||
* A new GuacamoleSocket which is configured and connected to the given
|
||||
* connection.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the connection cannot be established due to concurrent usage
|
||||
* rules.
|
||||
*/
|
||||
@Override
|
||||
public GuacamoleSocket getGuacamoleSocket(final AuthenticatedUser user,
|
||||
final MySQLConnection connection, GuacamoleClientInformation info)
|
||||
throws GuacamoleException {
|
||||
|
||||
// Generate configuration from available data
|
||||
GuacamoleConfiguration config = new GuacamoleConfiguration();
|
||||
|
||||
// Set protocol from connection
|
||||
ConnectionModel model = connection.getModel();
|
||||
config.setProtocol(model.getProtocol());
|
||||
|
||||
// Set parameters from associated data
|
||||
Collection<ParameterModel> parameters = parameterMapper.select(connection.getIdentifier());
|
||||
for (ParameterModel parameter : parameters)
|
||||
config.setParameter(parameter.getName(), parameter.getValue());
|
||||
|
||||
// Return new socket
|
||||
try {
|
||||
|
||||
// Atomically gain access to connection
|
||||
acquire(user, connection);
|
||||
incrementUsage(connection);
|
||||
|
||||
// Return newly-reserved connection
|
||||
return new ConfiguredGuacamoleSocket(
|
||||
new InetGuacamoleSocket(
|
||||
environment.getRequiredProperty(Environment.GUACD_HOSTNAME),
|
||||
environment.getRequiredProperty(Environment.GUACD_PORT)
|
||||
),
|
||||
config
|
||||
) {
|
||||
|
||||
@Override
|
||||
public void close() throws GuacamoleException {
|
||||
|
||||
// Attempt to close connection
|
||||
super.close();
|
||||
|
||||
// Release connection upon close
|
||||
decrementUsage(connection);
|
||||
release(user, connection);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
// Release connection in case of error
|
||||
catch (GuacamoleException e) {
|
||||
|
||||
// Atomically release access to connection
|
||||
decrementUsage(connection);
|
||||
release(user, connection);
|
||||
|
||||
throw e;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getActiveConnections(Connection connection) {
|
||||
|
||||
// If no such active connection, zero active users
|
||||
AtomicInteger count = activeConnectionCount.get(connection.getIdentifier());
|
||||
if (count == null)
|
||||
return 0;
|
||||
|
||||
// Otherwise, return stored value
|
||||
return count.intValue();
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -24,8 +24,6 @@ package net.sourceforge.guacamole.net.auth.mysql.service;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Provider;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -39,17 +37,13 @@ import net.sourceforge.guacamole.net.auth.mysql.model.ParameterModel;
|
||||
import org.glyptodon.guacamole.GuacamoleClientException;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.GuacamoleSecurityException;
|
||||
import org.glyptodon.guacamole.environment.Environment;
|
||||
import org.glyptodon.guacamole.net.GuacamoleSocket;
|
||||
import org.glyptodon.guacamole.net.InetGuacamoleSocket;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
|
||||
import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet;
|
||||
import org.glyptodon.guacamole.protocol.ConfiguredGuacamoleSocket;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
@@ -59,12 +53,6 @@ import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
|
||||
*/
|
||||
public class ConnectionService extends DirectoryObjectService<MySQLConnection, Connection, ConnectionModel> {
|
||||
|
||||
/**
|
||||
* The environment of the Guacamole server.
|
||||
*/
|
||||
@Inject
|
||||
private Environment environment;
|
||||
|
||||
/**
|
||||
* Mapper for accessing connections.
|
||||
*/
|
||||
@@ -83,6 +71,12 @@ public class ConnectionService extends DirectoryObjectService<MySQLConnection, C
|
||||
@Inject
|
||||
private Provider<MySQLConnection> mySQLConnectionProvider;
|
||||
|
||||
/**
|
||||
* Service for creating and tracking sockets.
|
||||
*/
|
||||
@Inject
|
||||
private GuacamoleSocketService socketService;
|
||||
|
||||
@Override
|
||||
protected DirectoryObjectMapper<ConnectionModel> getObjectMapper() {
|
||||
return connectionMapper;
|
||||
@@ -252,33 +246,9 @@ public class ConnectionService extends DirectoryObjectService<MySQLConnection, C
|
||||
MySQLConnection connection, GuacamoleClientInformation info)
|
||||
throws GuacamoleException {
|
||||
|
||||
String identifier = connection.getIdentifier();
|
||||
|
||||
// Connect only if READ permission is granted
|
||||
if (hasObjectPermission(user, identifier, ObjectPermission.Type.READ)) {
|
||||
|
||||
// Generate configuration from available data
|
||||
GuacamoleConfiguration config = new GuacamoleConfiguration();
|
||||
|
||||
// Set protocol from connection
|
||||
ConnectionModel model = connection.getModel();
|
||||
config.setProtocol(model.getProtocol());
|
||||
|
||||
// Set parameters from associated data
|
||||
Collection<ParameterModel> parameters = parameterMapper.select(identifier);
|
||||
for (ParameterModel parameter : parameters)
|
||||
config.setParameter(parameter.getName(), parameter.getValue());
|
||||
|
||||
// Return new socket
|
||||
return new ConfiguredGuacamoleSocket(
|
||||
new InetGuacamoleSocket(
|
||||
environment.getRequiredProperty(Environment.GUACD_HOSTNAME),
|
||||
environment.getRequiredProperty(Environment.GUACD_PORT)
|
||||
),
|
||||
config
|
||||
);
|
||||
|
||||
}
|
||||
if (hasObjectPermission(user, connection.getIdentifier(), ObjectPermission.Type.READ))
|
||||
return socketService.getGuacamoleSocket(user, connection, info);
|
||||
|
||||
// The user does not have permission to connect
|
||||
throw new GuacamoleSecurityException("Permission denied.");
|
||||
|
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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 net.sourceforge.guacamole.net.auth.mysql.service;
|
||||
|
||||
import net.sourceforge.guacamole.net.auth.mysql.AuthenticatedUser;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.MySQLConnection;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
import org.glyptodon.guacamole.net.GuacamoleSocket;
|
||||
import org.glyptodon.guacamole.net.auth.Connection;
|
||||
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
|
||||
|
||||
|
||||
/**
|
||||
* Service which creates pre-configured GuacamoleSocket instances for
|
||||
* connections and balancing groups, applying concurrent usage rules.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
public interface GuacamoleSocketService {
|
||||
|
||||
/**
|
||||
* Creates a socket for the given user which connects to the given
|
||||
* connection. The given client information will be passed to guacd when
|
||||
* the connection is established. This function will apply any concurrent
|
||||
* usage rules in effect, but will NOT test object- or system-level
|
||||
* permissions.
|
||||
*
|
||||
* @param user
|
||||
* The user for whom the connection is being established.
|
||||
*
|
||||
* @param connection
|
||||
* The connection the user is connecting to.
|
||||
*
|
||||
* @param info
|
||||
* Information describing the Guacamole client connecting to the given
|
||||
* connection.
|
||||
*
|
||||
* @return
|
||||
* A new GuacamoleSocket which is configured and connected to the given
|
||||
* connection.
|
||||
*
|
||||
* @throws GuacamoleException
|
||||
* If the connection cannot be established due to concurrent usage
|
||||
* rules.
|
||||
*/
|
||||
GuacamoleSocket getGuacamoleSocket(AuthenticatedUser user,
|
||||
MySQLConnection connection, GuacamoleClientInformation info)
|
||||
throws GuacamoleException;
|
||||
|
||||
/**
|
||||
* Returns the number of active connections using the given connection.
|
||||
*
|
||||
* @param connection
|
||||
* The connection to check.
|
||||
*
|
||||
* @return
|
||||
* The number of active connections using the given connection.
|
||||
*/
|
||||
public int getActiveConnections(Connection connection);
|
||||
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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 net.sourceforge.guacamole.net.auth.mysql.service;
|
||||
|
||||
import com.google.inject.Singleton;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.AuthenticatedUser;
|
||||
import net.sourceforge.guacamole.net.auth.mysql.MySQLConnection;
|
||||
import org.glyptodon.guacamole.GuacamoleException;
|
||||
|
||||
|
||||
/**
|
||||
* GuacamoleSocketService implementation which imposes no restrictions
|
||||
* whatsoever on the number of concurrent or duplicate connections.
|
||||
*
|
||||
* @author Michael Jumper
|
||||
*/
|
||||
@Singleton
|
||||
public class UnrestrictedGuacamoleSocketService
|
||||
extends AbstractGuacamoleSocketService {
|
||||
|
||||
@Override
|
||||
protected void acquire(AuthenticatedUser user, MySQLConnection connection)
|
||||
throws GuacamoleException {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void release(AuthenticatedUser user, MySQLConnection connection) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user