Ticket #263: More work on connection groups.

This commit is contained in:
James Muehlner
2013-08-06 23:39:30 -07:00
parent 6747c51b38
commit bdc7a3db96
15 changed files with 778 additions and 107 deletions

View File

@@ -66,6 +66,11 @@ public class ConnectionDirectory implements Directory<String, Connection>{
*/ */
private int user_id; private int user_id;
/**
* The ID of the parent connection group.
*/
private Integer parentID;
/** /**
* Service for checking permissions. * Service for checking permissions.
*/ */
@@ -91,21 +96,23 @@ public class ConnectionDirectory implements Directory<String, Connection>{
private ConnectionParameterMapper connectionParameterDAO; private ConnectionParameterMapper connectionParameterDAO;
/** /**
* Set the user for this directory. * Set the user and parentID for this directory.
* *
* @param user_id The ID of the user owning this connection directory. * @param user_id The ID of the user owning this connection directory.
* @param parentID The ID of the parent connection group.
*/ */
public void init(int user_id) { public void init(int user_id, Integer parentID) {
this.parentID = parentID;
this.user_id = user_id; this.user_id = user_id;
} }
@Transactional @Transactional
@Override @Override
public Connection get(String identifier) throws GuacamoleException { public Connection get(String name) throws GuacamoleException {
// Get connection // Get connection
MySQLConnection connection = MySQLConnection connection =
connectionService.retrieveConnection(identifier, user_id); connectionService.retrieveConnection(name, parentID, user_id);
// Verify access is granted // Verify access is granted
permissionCheckService.verifyConnectionAccess( permissionCheckService.verifyConnectionAccess(
@@ -121,8 +128,13 @@ public class ConnectionDirectory implements Directory<String, Connection>{
@Transactional @Transactional
@Override @Override
public Set<String> getIdentifiers() throws GuacamoleException { public Set<String> getIdentifiers() throws GuacamoleException {
// Verify permission to use the connection group for organizational purposes
permissionCheckService.verifyConnectionGroupUsageAccess
(parentID, user_id, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
return permissionCheckService.retrieveConnectionNames(user_id, return permissionCheckService.retrieveConnectionNames(user_id,
MySQLConstants.CONNECTION_READ); parentID, MySQLConstants.CONNECTION_READ);
} }
@Transactional @Transactional
@@ -137,9 +149,17 @@ public class ConnectionDirectory implements Directory<String, Connection>{
permissionCheckService.verifySystemAccess(this.user_id, permissionCheckService.verifySystemAccess(this.user_id,
MySQLConstants.SYSTEM_CONNECTION_CREATE); MySQLConstants.SYSTEM_CONNECTION_CREATE);
// Verify permission to edit the connection group
permissionCheckService.verifyConnectionGroupAccess(this.user_id,
this.parentID, MySQLConstants.CONNECTION_GROUP_UPDATE);
// Verify permission to use the connection group for organizational purposes
permissionCheckService.verifyConnectionGroupUsageAccess
(parentID, user_id, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
// Verify that no connection already exists with this identifier. // Verify that no connection already exists with this identifier.
MySQLConnection previousConnection = MySQLConnection previousConnection =
connectionService.retrieveConnection(identifier, user_id); connectionService.retrieveConnection(identifier, user_id, parentID);
if(previousConnection != null) if(previousConnection != null)
throw new GuacamoleClientException("That connection identifier is already in use."); throw new GuacamoleClientException("That connection identifier is already in use.");
@@ -198,7 +218,6 @@ public class ConnectionDirectory implements Directory<String, Connection>{
// Insert connection parameter // Insert connection parameter
connectionParameterDAO.insert(parameter); connectionParameterDAO.insert(parameter);
} }
} }
@@ -239,7 +258,7 @@ public class ConnectionDirectory implements Directory<String, Connection>{
// Get connection // Get connection
MySQLConnection mySQLConnection = MySQLConnection mySQLConnection =
connectionService.retrieveConnection(identifier, user_id); connectionService.retrieveConnection(identifier, parentID, user_id);
// Verify permission to delete // Verify permission to delete
permissionCheckService.verifyConnectionAccess(this.user_id, permissionCheckService.verifyConnectionAccess(this.user_id,

View File

@@ -0,0 +1,146 @@
package net.sourceforge.guacamole.net.auth.mysql;
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is guacamole-auth-mysql.
*
* The Initial Developer of the Original Code is
* James Muehlner.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
import com.google.inject.Inject;
import java.util.Set;
import net.sourceforge.guacamole.GuacamoleClientException;
import net.sourceforge.guacamole.GuacamoleException;
import net.sourceforge.guacamole.net.auth.Connection;
import net.sourceforge.guacamole.net.auth.ConnectionGroup;
import net.sourceforge.guacamole.net.auth.Directory;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionParameterMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionPermissionMapper;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionParameter;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionParameterExample;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionPermissionKey;
import net.sourceforge.guacamole.net.auth.mysql.service.ConnectionGroupService;
import net.sourceforge.guacamole.net.auth.mysql.service.PermissionCheckService;
import net.sourceforge.guacamole.protocol.GuacamoleConfiguration;
import org.mybatis.guice.transactional.Transactional;
/**
* A MySQL-based implementation of the connection group directory.
*
* @author James Muehlner
*/
public class ConnectionGroupDirectory implements Directory<String, ConnectionGroup>{
/**
* The ID of the user who this connection directory belongs to.
* Access is based on his/her permission settings.
*/
private int user_id;
/**
* The ID of the parent connection for this connection.
*/
private Integer parentID;
/**
* Service for checking permissions.
*/
@Inject
private PermissionCheckService permissionCheckService;
/**
* Service managing connection groups.
*/
@Inject
private ConnectionGroupService connectionGroupService;
/**
* Service for manipulating connection permissions in the database.
*/
@Inject
private ConnectionPermissionMapper connectionPermissionDAO;
/**
* Service for manipulating connection parameters in the database.
*/
@Inject
private ConnectionParameterMapper connectionParameterDAO;
@Transactional
@Override
public ConnectionGroup get(String name) throws GuacamoleException {
// Get connection
MySQLConnectionGroup connectionGroup =
connectionGroupService.retrieveConnectionGroup(name, parentID, user_id);
// Verify access is granted
permissionCheckService.verifyConnectionGroupAccess(
this.user_id,
connectionGroup.getConnectionGroupID(),
MySQLConstants.CONNECTION_GROUP_READ);
// Return connection group
return connectionGroup;
}
@Transactional
@Override
public Set<String> getIdentifiers() throws GuacamoleException {
// Verify permission to use the connection group for organizational purposes
permissionCheckService.verifyConnectionGroupUsageAccess
(parentID, user_id, MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL);
return permissionCheckService.retrieveConnectionGroupNames(user_id,
parentID, MySQLConstants.CONNECTION_GROUP_READ);
}
@Override
public void add(ConnectionGroup object) throws GuacamoleException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void update(ConnectionGroup object) throws GuacamoleException {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void remove(String identifier) throws GuacamoleException {
throw new UnsupportedOperationException("Not supported yet.");
}
}

View File

@@ -61,7 +61,7 @@ public class MySQLConnection extends AbstractConnection {
private Integer connectionID; private Integer connectionID;
/** /**
* The ID of the parent connection for this connection group. * The ID of the parent connection for this connection.
*/ */
private Integer parentID; private Integer parentID;
@@ -129,12 +129,13 @@ public class MySQLConnection extends AbstractConnection {
* @param history All ConnectionRecords associated with this connection. * @param history All ConnectionRecords associated with this connection.
* @param userID The IID of the user who queried this connection. * @param userID The IID of the user who queried this connection.
*/ */
public void init(Integer connectionID, Integer parentID, String identifier, public void init(Integer connectionID, Integer parentID, String name,
GuacamoleConfiguration config, String identifier, GuacamoleConfiguration config,
List<? extends ConnectionRecord> history, int userID) { List<? extends ConnectionRecord> history, int userID) {
this.connectionID = connectionID; this.connectionID = connectionID;
this.parentID = parentID; this.parentID = parentID;
setName(name);
setIdentifier(identifier); setIdentifier(identifier);
setConfiguration(config); setConfiguration(config);
this.history.addAll(history); this.history.addAll(history);

View File

@@ -38,6 +38,7 @@ package net.sourceforge.guacamole.net.auth.mysql;
* ***** END LICENSE BLOCK ***** */ * ***** END LICENSE BLOCK ***** */
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider;
import net.sourceforge.guacamole.GuacamoleException; import net.sourceforge.guacamole.GuacamoleException;
import net.sourceforge.guacamole.net.GuacamoleSocket; import net.sourceforge.guacamole.net.GuacamoleSocket;
import net.sourceforge.guacamole.net.auth.AbstractConnectionGroup; import net.sourceforge.guacamole.net.auth.AbstractConnectionGroup;
@@ -65,6 +66,11 @@ public class MySQLConnectionGroup extends AbstractConnectionGroup {
*/ */
private Integer parentID; private Integer parentID;
/**
* The type of this connection group.
*/
private String type;
/** /**
* The ID of the user who queried or created this connection group. * The ID of the user who queried or created this connection group.
*/ */
@@ -73,12 +79,12 @@ public class MySQLConnectionGroup extends AbstractConnectionGroup {
/** /**
* A Directory of connections that have this connection group as a parent. * A Directory of connections that have this connection group as a parent.
*/ */
private Directory<String, Connection> connectionDirectory = null; private ConnectionDirectory connectionDirectory = null;
/** /**
* A Directory of connection groups that have this connection group as a parent. * A Directory of connection groups that have this connection group as a parent.
*/ */
private Directory<String, ConnectionGroup> connectionGroupDirectory = null; private ConnectionGroupDirectory connectionGroupDirectory = null;
/** /**
* Service managing connections. * Service managing connections.
@@ -98,6 +104,16 @@ public class MySQLConnectionGroup extends AbstractConnectionGroup {
@Inject @Inject
private PermissionCheckService permissionCheckService; private PermissionCheckService permissionCheckService;
/**
* Service for creating new ConnectionDirectory objects.
*/
@Inject Provider<ConnectionDirectory> connectionDirectoryProvider;
/**
* Service for creating new ConnectionGroupDirectory objects.
*/
@Inject Provider<ConnectionGroupDirectory> connectionGroupDirectoryProvider;
/** /**
* Create a default, empty connection group. * Create a default, empty connection group.
*/ */
@@ -140,42 +156,74 @@ public class MySQLConnectionGroup extends AbstractConnectionGroup {
* Initialize from explicit values. * Initialize from explicit values.
* *
* @param connectionGroupID The ID of the associated database record, if any. * @param connectionGroupID The ID of the associated database record, if any.
* @param parentID The D of the parent connection group for this connection group, if any. * @param parentID The ID of the parent connection group for this connection group, if any.
* @param identifier The unique identifier associated with this connection group. * @param identifier The unique identifier associated with this connection group.
* @param type The type of this connection group.
* @param userID The IID of the user who queried this connection. * @param userID The IID of the user who queried this connection.
*/ */
public void init(Integer connectionGroupID, Integer parentID, String identifier, int userID) { public void init(Integer connectionGroupID, Integer parentID, String name,
String identifier, String type, int userID) {
this.connectionGroupID = connectionGroupID; this.connectionGroupID = connectionGroupID;
this.parentID = parentID; this.parentID = parentID;
setName(name);
setIdentifier(identifier); setIdentifier(identifier);
this.type = type;
this.userID = userID; this.userID = userID;
connectionDirectory = connectionDirectoryProvider.get();
connectionDirectory.init(userID, parentID);
connectionGroupDirectory = connectionGroupDirectoryProvider.get();
//connectionGroupDirectory.init(userID, parentID);
} }
@Override @Override
public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException { public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException {
// Verify permission to use the connection group for balancing purposes
permissionCheckService.verifyConnectionGroupUsageAccess
(this.connectionGroupID, this.userID, MySQLConstants.CONNECTION_GROUP_BALANCING);
return connectionGroupService.connect(this, info, userID); return connectionGroupService.connect(this, info, userID);
} }
private void loadConnectionDirectory() {
}
@Override @Override
public Directory<String, Connection> getConnectionDirectory() throws GuacamoleException { public Directory<String, Connection> getConnectionDirectory() throws GuacamoleException {
if(connectionDirectory == null)
loadConnectionDirectory();
return connectionDirectory; return connectionDirectory;
} }
private void loadConnectionGroupDirectory() {
}
@Override @Override
public Directory<String, ConnectionGroup> getConnectionGroupDirectory() throws GuacamoleException { public Directory<String, ConnectionGroup> getConnectionGroupDirectory() throws GuacamoleException {
if(connectionGroupDirectory == null)
loadConnectionGroupDirectory();
return connectionGroupDirectory; return connectionGroupDirectory;
} }
/**
* Returns the connection group type.
* @return the connection group type.
*/
public String getType() {
return type;
}
/**
* Sets the connection group type.
* @param type the connection group type.
*/
public void setType(String type) {
this.type = type;
}
@Override
public void setBalancing(boolean balancing) {
if(balancing)
this.type = MySQLConstants.CONNECTION_GROUP_BALANCING;
else
this.type = MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL;
}
@Override
public boolean isBalancing() {
return MySQLConstants.CONNECTION_GROUP_BALANCING.equals(this.type);
}
} }

View File

@@ -96,6 +96,43 @@ public final class MySQLConstants {
*/ */
public static final String CONNECTION_ADMINISTER = "ADMINISTER"; public static final String CONNECTION_ADMINISTER = "ADMINISTER";
/**
* The string stored in the database to represent READ access to a
* connection.
*/
public static final String CONNECTION_GROUP_READ = "READ";
/**
* The string stored in the database to represent UPDATE access to a
* connection group.
*/
public static final String CONNECTION_GROUP_UPDATE = "UPDATE";
/**
* The string stored in the database to represent DELETE access to a
* connection group.
*/
public static final String CONNECTION_GROUP_DELETE = "DELETE";
/**
* The string stored in the database to represent ADMINISTER access to a
* connection group.
*/
public static final String CONNECTION_GROUP_ADMINISTER = "ADMINISTER";
/**
* The string stored in the database to represent a BALANCING
* connection group.
*/
public static final String CONNECTION_GROUP_BALANCING = "BALANCING";
/**
* The string stored in the database to represent an ORGANIZATIONAL
* connection group.
*/
public static final String CONNECTION_GROUP_ORGANIZATIONAL =
"ORGANIZATIONAL";
/** /**
* The string stored in the database to represent permission to create * The string stored in the database to represent permission to create
* users. * users.
@@ -160,6 +197,28 @@ public final class MySQLConstants {
} }
/**
* Given the type of a permission affecting a connection group,
* returns the MySQL constant representing that permission type.
*
* @param type The type of permission to look up.
* @return The MySQL constant corresponding to the given permission type.
*/
public static String getConnectionGroupConstant(ObjectPermission.Type type) {
// Convert permission type to MySQL constant
switch (type) {
case READ: return CONNECTION_GROUP_READ;
case UPDATE: return CONNECTION_GROUP_UPDATE;
case ADMINISTER: return CONNECTION_GROUP_ADMINISTER;
case DELETE: return CONNECTION_GROUP_DELETE;
}
// If we get here, permission support was not properly implemented
throw new UnsupportedOperationException(
"Unsupported permission type: " + type);
}
/** /**
* Given the type of a permission affecting the system, returns the MySQL * Given the type of a permission affecting the system, returns the MySQL

View File

@@ -49,10 +49,13 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import net.sourceforge.guacamole.net.GuacamoleSocket; import net.sourceforge.guacamole.net.GuacamoleSocket;
import net.sourceforge.guacamole.net.auth.mysql.MySQLConnection;
import net.sourceforge.guacamole.net.auth.mysql.MySQLConnectionGroup; import net.sourceforge.guacamole.net.auth.mysql.MySQLConnectionGroup;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionGroupMapper; import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionGroupMapper;
import net.sourceforge.guacamole.net.auth.mysql.model.Connection;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroup; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroup;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupExample; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupExample;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupExample.Criteria;
import net.sourceforge.guacamole.protocol.GuacamoleClientInformation; import net.sourceforge.guacamole.protocol.GuacamoleClientInformation;
/** /**
@@ -76,32 +79,60 @@ public class ConnectionGroupService {
private Provider<MySQLConnectionGroup> mysqlConnectionGroupProvider; private Provider<MySQLConnectionGroup> mysqlConnectionGroupProvider;
/** /**
* Retrieves all connection groups with a given parent connection group ID. * Retrieves the connection group having the given
* name from the database.
* *
* @param parentID The parent ID of the connection groups. * @param name The name of the connection to return.
* @param userID The ID of the user who queried these connection groups. * @param parentID The ID of the parent connection group.
* @return All connection groups with a given parent connection group ID. * @param userID The ID of the user who queried this connection group.
* @return The connection having the given name, or null if no such
* connection group could be found.
*/ */
public Collection<MySQLConnectionGroup> getConnectionGroupsByParentConnectionGroup(Integer parentID, int userID) { public MySQLConnectionGroup retrieveConnectionGroup(String name, Integer parentID,
int userID) {
// A null parentID indicates the root-level group // Create criteria
ConnectionGroupExample example = new ConnectionGroupExample(); ConnectionGroupExample example = new ConnectionGroupExample();
Criteria criteria = example.createCriteria().andConnection_group_nameEqualTo(name);
if(parentID != null) if(parentID != null)
example.createCriteria().andParent_group_idEqualTo(parentID); criteria.andParent_idEqualTo(parentID);
else else
example.createCriteria().andParent_group_idIsNull(); criteria.andParent_idIsNull();
// Get all connections with the given parent ID // Query connection group by name and parentID
List<ConnectionGroup> connectionGroups = connectionGroupDAO.selectByExample(example); List<ConnectionGroup> connectionGroups =
connectionGroupDAO.selectByExample(example);
List<MySQLConnectionGroup> mySQLConnectionGroups = new ArrayList<MySQLConnectionGroup>(); // If no connection group found, return null
if(connectionGroups.isEmpty())
return null;
// Otherwise, return found connection
return toMySQLConnectionGroup(connectionGroups.get(0), userID);
for(ConnectionGroup connectionGroup : connectionGroups) {
mySQLConnectionGroups.add(toMySQLConnectionGroup(connectionGroup, userID));
} }
return mySQLConnectionGroups; /**
* Retrieves the connection group having the given ID from the database.
*
* @param id The ID of the connection group to retrieve.
* @param userID The ID of the user who queried this connection.
* @return The connection group having the given ID, or null if no such
* connection was found.
*/
public MySQLConnectionGroup retrieveConnectionGroup(int id, int userID) {
// Query connection by ID
ConnectionGroup connectionGroup = connectionGroupDAO.selectByPrimaryKey(id);
// If no connection found, return null
if(connectionGroup == null)
return null;
// Otherwise, return found connection
return toMySQLConnectionGroup(connectionGroup, userID);
} }
public GuacamoleSocket connect(MySQLConnectionGroup group, public GuacamoleSocket connect(MySQLConnectionGroup group,
@@ -159,6 +190,66 @@ public class ConnectionGroupService {
} }
/**
* Retrieves a translation map of connection group names to their
* corresponding IDs.
*
* @param ids The IDs of the connection groups to retrieve the names of.
* @return A map containing the names of all connection groups and their
* corresponding IDs.
*/
public Map<String, Integer> translateNames(List<Integer> ids) {
// If no IDs given, just return empty map
if (ids.isEmpty())
return Collections.EMPTY_MAP;
// Map of all names onto their corresponding IDs.
Map<String, Integer> names = new HashMap<String, Integer>();
// Get all connections having the given IDs
ConnectionGroupExample example = new ConnectionGroupExample();
example.createCriteria().andConnection_group_idIn(ids);
List<ConnectionGroup> connectionGroups = connectionGroupDAO.selectByExample(example);
// Produce set of names
for (ConnectionGroup connectionGroup : connectionGroups)
names.put(connectionGroup.getConnection_group_name(),
connectionGroup.getConnection_group_id());
return names;
}
/**
* Returns a list of the IDs of all connection groups with a given parent ID.
* @param parentID The ID of the parent for all the queried connection groups.
* @return a list of the IDs of all connection groups with a given parent ID.
*/
public List<Integer> getAllConnectionGroupIDs(Integer parentID) {
// Create criteria
ConnectionGroupExample example = new ConnectionGroupExample();
Criteria criteria = example.createCriteria();
if(parentID != null)
criteria.andConnection_group_idEqualTo(parentID);
else
criteria.andConnection_group_idIsNull();
// Query the connections
List<ConnectionGroup> connectionGroups = connectionGroupDAO.selectByExample(example);
// List of IDs of connections with the given parent
List<Integer> connectionGroupIDs = new ArrayList<Integer>();
for(ConnectionGroup connectionGroup : connectionGroups) {
connectionGroupIDs.add(connectionGroup.getConnection_group_id());
}
return connectionGroupIDs;
}
/** /**
* Convert the given database-retrieved Connection into a MySQLConnection. * Convert the given database-retrieved Connection into a MySQLConnection.
* The parameters of the given connection will be read and added to the * The parameters of the given connection will be read and added to the
@@ -175,8 +266,10 @@ public class ConnectionGroupService {
MySQLConnectionGroup mySQLConnectionGroup = mysqlConnectionGroupProvider.get(); MySQLConnectionGroup mySQLConnectionGroup = mysqlConnectionGroupProvider.get();
mySQLConnectionGroup.init( mySQLConnectionGroup.init(
connectionGroup.getConnection_group_id(), connectionGroup.getConnection_group_id(),
connectionGroup.getParent_group_id(), connectionGroup.getParent_id(),
connectionGroup.getConnection_group_name(), connectionGroup.getConnection_group_name(),
Integer.toString(connectionGroup.getConnection_group_id()),
connectionGroup.getType(),
userID userID
); );

View File

@@ -63,6 +63,7 @@ import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionParameterMapper; import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionParameterMapper;
import net.sourceforge.guacamole.net.auth.mysql.model.Connection; import net.sourceforge.guacamole.net.auth.mysql.model.Connection;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionExample; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionExample;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionExample.Criteria;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionHistory; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionHistory;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionHistoryExample; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionHistoryExample;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionParameter; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionParameter;
@@ -128,15 +129,23 @@ public class ConnectionService {
* Retrieves the connection having the given name from the database. * Retrieves the connection having the given name from the database.
* *
* @param name The name of the connection to return. * @param name The name of the connection to return.
* @param parentID The ID of the parent connection group.
* @param userID The ID of the user who queried this connection. * @param userID The ID of the user who queried this connection.
* @return The connection having the given name, or null if no such * @return The connection having the given name, or null if no such
* connection could be found. * connection could be found.
*/ */
public MySQLConnection retrieveConnection(String name, int userID) { public MySQLConnection retrieveConnection(String name, Integer parentID,
int userID) {
// Query connection by connection identifier (name) // Create criteria
ConnectionExample example = new ConnectionExample(); ConnectionExample example = new ConnectionExample();
example.createCriteria().andConnection_nameEqualTo(name); Criteria criteria = example.createCriteria().andConnection_nameEqualTo(name);
if(parentID != null)
criteria.andParent_idEqualTo(parentID);
else
criteria.andParent_idIsNull();
// Query connection by name and parentID
List<Connection> connections = List<Connection> connections =
connectionDAO.selectByExample(example); connectionDAO.selectByExample(example);
@@ -144,9 +153,6 @@ public class ConnectionService {
if(connections.isEmpty()) if(connections.isEmpty())
return null; return null;
// Assert only one connection found
assert connections.size() == 1 : "Multiple connections with same name.";
// Otherwise, return found connection // Otherwise, return found connection
return toMySQLConnection(connections.get(0), userID); return toMySQLConnection(connections.get(0), userID);
@@ -173,34 +179,6 @@ public class ConnectionService {
return toMySQLConnection(connection, userID); return toMySQLConnection(connection, userID);
} }
/**
* Retrieves all connections with a given parent connection group ID.
*
* @param parentID The parent ID of the connections.
* @param userID The ID of the user who queried these connections.
* @return All connections with a given parent connection group ID.
*/
public Collection<MySQLConnection> getConnectionsByParentConnectionGroup(Integer parentID, int userID) {
// A null parentID indicates the root-level group
ConnectionExample example = new ConnectionExample();
if(parentID != null)
example.createCriteria().andConnection_group_idEqualTo(parentID);
else
example.createCriteria().andConnection_group_idIsNull();
// Get all connections with the given parent ID
List<Connection> connections = connectionDAO.selectByExample(example);
List<MySQLConnection> mySQLConnections = new ArrayList<MySQLConnection>();
for(Connection connection : connections) {
mySQLConnections.add(toMySQLConnection(connection, userID));
}
return mySQLConnections;
}
/** /**
* Retrieves a translation map of connection names to their corresponding * Retrieves a translation map of connection names to their corresponding
* IDs. * IDs.
@@ -262,6 +240,35 @@ public class ConnectionService {
} }
/**
* Returns a list of the IDs of all connections with a given parent ID.
* @param parentID The ID of the parent for all the queried connections.
* @return a list of the IDs of all connections with a given parent ID.
*/
public List<Integer> getAllConnectionIDs(Integer parentID) {
// Create criteria
ConnectionExample example = new ConnectionExample();
Criteria criteria = example.createCriteria();
if(parentID != null)
criteria.andConnection_idEqualTo(parentID);
else
criteria.andConnection_idIsNull();
// Query the connections
List<Connection> connections = connectionDAO.selectByExample(example);
// List of IDs of connections with the given parent
List<Integer> connectionIDs = new ArrayList<Integer>();
for(Connection connection : connections) {
connectionIDs.add(connection.getConnection_id());
}
return connectionIDs;
}
/** /**
* Convert the given database-retrieved Connection into a MySQLConnection. * Convert the given database-retrieved Connection into a MySQLConnection.
* The parameters of the given connection will be read and added to the * The parameters of the given connection will be read and added to the
@@ -295,8 +302,9 @@ public class ConnectionService {
MySQLConnection mySQLConnection = mySQLConnectionProvider.get(); MySQLConnection mySQLConnection = mySQLConnectionProvider.get();
mySQLConnection.init( mySQLConnection.init(
connection.getConnection_id(), connection.getConnection_id(),
connection.getConnection_group_id(), connection.getParent_id(),
connection.getConnection_name(), connection.getConnection_name(),
Integer.toString(connection.getConnection_id()),
config, config,
retrieveHistory(connection.getConnection_id()), retrieveHistory(connection.getConnection_id()),
userID userID
@@ -451,18 +459,28 @@ public class ConnectionService {
} }
/** /**
* Get the names of all the connections defined in the system. * Get the names of all the connections defined in the system
* with a certain parentID.
* *
* @return A Set of names of all the connections defined in the system. * @return A Set of names of all the connections defined in the system
* with the given parentID.
*/ */
public Set<String> getAllConnectionNames() { public Set<String> getAllConnectionNames(Integer parentID) {
// Set of all present connection names // Set of all present connection names
Set<String> names = new HashSet<String>(); Set<String> names = new HashSet<String>();
// Query all connection names // Set up Criteria
ConnectionExample example = new ConnectionExample();
Criteria criteria = example.createCriteria();
if(parentID != null)
criteria.andParent_idEqualTo(parentID);
else
criteria.andParent_idIsNull();
// Query connection names
List<Connection> connections = List<Connection> connections =
connectionDAO.selectByExample(new ConnectionExample()); connectionDAO.selectByExample(example);
for (Connection connection : connections) for (Connection connection : connections)
names.add(connection.getConnection_name()); names.add(connection.getConnection_name());
@@ -471,7 +489,10 @@ public class ConnectionService {
} }
/** /**
* Get the connection IDs of all the connections defined in the system. * Get the connection IDs of all the connections defined in the system
* with a certain parent connection group.
*
* @param parentID The parent connection group ID.
* *
* @return A list of connection IDs of all the connections defined in the system. * @return A list of connection IDs of all the connections defined in the system.
*/ */
@@ -480,9 +501,17 @@ public class ConnectionService {
// Set of all present connection IDs // Set of all present connection IDs
List<Integer> connectionIDs = new ArrayList<Integer>(); List<Integer> connectionIDs = new ArrayList<Integer>();
// Query all connection IDs // Create the criteria
ConnectionExample example = new ConnectionExample();
/*Criteria criteria = example.createCriteria();
if(parentID != null)
criteria.andParent_idEqualTo(parentID);
else
criteria.andParent_idIsNull();*/
// Query the connections
List<Connection> connections = List<Connection> connections =
connectionDAO.selectByExample(new ConnectionExample()); connectionDAO.selectByExample(example);
for (Connection connection : connections) for (Connection connection : connections)
connectionIDs.add(connection.getConnection_id()); connectionIDs.add(connection.getConnection_id());

View File

@@ -42,6 +42,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import net.sourceforge.guacamole.GuacamoleSecurityException; import net.sourceforge.guacamole.GuacamoleSecurityException;
import net.sourceforge.guacamole.net.auth.mysql.MySQLConnectionGroup;
import net.sourceforge.guacamole.net.auth.mysql.MySQLConstants; import net.sourceforge.guacamole.net.auth.mysql.MySQLConstants;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionGroupPermissionMapper; import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionGroupPermissionMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionPermissionMapper; import net.sourceforge.guacamole.net.auth.mysql.dao.ConnectionPermissionMapper;
@@ -50,6 +51,7 @@ import net.sourceforge.guacamole.net.auth.mysql.dao.UserPermissionMapper;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupPermissionExample; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupPermissionExample;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupPermissionKey; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupPermissionKey;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionPermissionExample; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionPermissionExample;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionPermissionExample.Criteria;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionPermissionKey; import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionPermissionKey;
import net.sourceforge.guacamole.net.auth.mysql.model.SystemPermissionExample; import net.sourceforge.guacamole.net.auth.mysql.model.SystemPermissionExample;
import net.sourceforge.guacamole.net.auth.mysql.model.SystemPermissionKey; import net.sourceforge.guacamole.net.auth.mysql.model.SystemPermissionKey;
@@ -290,6 +292,69 @@ public class PermissionCheckService {
return systemPermissionDAO.countByExample(example) > 0; return systemPermissionDAO.countByExample(example) > 0;
} }
/**
* Verifies that the specified group can be used for organization
* by the given user.
*
* @param connectionGroupID The ID of the affected ConnectionGroup.
* @param userID The ID of the user to check.
* @throws GuacamoleSecurityException If the connection group
* cannot be used for organization.
*/
public void verifyConnectionGroupUsageAccess(Integer connectionGroupID,
int userID, String type) throws GuacamoleSecurityException {
// If permission does not exist, throw exception
if(!checkConnectionGroupUsageAccess(connectionGroupID, userID, type))
throw new GuacamoleSecurityException("Permission denied.");
}
/**
* Check whether a user can use connectionGroup for the given usage.
* @param connectionGroupID the ID of the affected connection group.
* @param userID The ID of the user to check.
* @param usage The desired usage.
* @return true if the user can use the connection group for the given usage.
*/
private boolean checkConnectionGroupUsageAccess(
Integer connectionGroupID, int userID, String usage) {
// The root level connection group can only be used for organization
if(connectionGroupID == null)
return MySQLConstants.CONNECTION_GROUP_ORGANIZATIONAL.equals(usage);
// A system administrator has full access to everything.
if(checkSystemAdministratorAccess(userID))
return true;
// Query the connection group
MySQLConnectionGroup connectionGroup = connectionGroupService.
retrieveConnectionGroup(connectionGroupID, userID);
// If the connection group is not found, it cannot be used.
if(connectionGroup == null)
return false;
// Verify that the desired usage matches the type.
return connectionGroup.getType().equals(usage);
}
/**
*
* @param userID
* @throws GuacamoleSecurityException
*/
private void verifySystemAdministratorAccess(int userID)
throws GuacamoleSecurityException {
// If permission does not exist, throw exception
if(!checkSystemAdministratorAccess(userID))
throw new GuacamoleSecurityException("Permission denied.");
}
/** /**
* Find the list of the IDs of all users a user has permission to. * Find the list of the IDs of all users a user has permission to.
* The access type is defined by permissionType. * The access type is defined by permissionType.
@@ -332,13 +397,61 @@ public class PermissionCheckService {
public List<Integer> retrieveConnectionIDs(int userID, public List<Integer> retrieveConnectionIDs(int userID,
String permissionType) { String permissionType) {
return retrieveConnectionIDs(userID, null, permissionType, false);
}
/**
* Find the list of the IDs of all connections a user has permission to.
* The access type is defined by permissionType.
*
* @param userID The ID of the user to check.
* @param parentID the parent connection group.
* @param permissionType The type of permission to check for.
* @return A list of all connection IDs this user has the specified access
* to.
*/
public List<Integer> retrieveConnectionIDs(int userID, Integer parentID,
String permissionType) {
return retrieveConnectionIDs(userID, parentID, permissionType, true);
}
/**
* Find the list of the IDs of all connections a user has permission to.
* The access type is defined by permissionType.
*
* @param userID The ID of the user to check.
* @param parentID the parent connection group.
* @param permissionType The type of permission to check for.
* @param checkParentID Whether the parentID should be checked or not.
* @return A list of all connection IDs this user has the specified access
* to.
*/
private List<Integer> retrieveConnectionIDs(int userID, Integer parentID,
String permissionType, boolean checkParentID) {
// A system administrator has access to all connections. // A system administrator has access to all connections.
if(checkSystemAdministratorAccess(userID)) if(checkSystemAdministratorAccess(userID)) {
if(checkParentID)
return connectionService.getAllConnectionIDs(parentID);
else
return connectionService.getAllConnectionIDs(); return connectionService.getAllConnectionIDs();
}
// Query all connection permissions for the given user and permission type // Query all connection permissions for the given user and permission type
ConnectionPermissionExample example = new ConnectionPermissionExample(); ConnectionPermissionExample example = new ConnectionPermissionExample();
example.createCriteria().andUser_idEqualTo(userID).andPermissionEqualTo(permissionType); Criteria criteria = example.createCriteria().andUser_idEqualTo(userID)
.andPermissionEqualTo(permissionType);
// Ensure that the connections are all under the parent ID, if needed
if(checkParentID) {
// Get the IDs of all connections in the connection group
List<Integer> allConnectionIDs = connectionService.getAllConnectionIDs(parentID);
criteria.andConnection_idIn(allConnectionIDs);
}
example.setDistinct(true); example.setDistinct(true);
List<ConnectionPermissionKey> connectionPermissions = List<ConnectionPermissionKey> connectionPermissions =
connectionPermissionDAO.selectByExample(example); connectionPermissionDAO.selectByExample(example);
@@ -364,13 +477,63 @@ public class PermissionCheckService {
public List<Integer> retrieveConnectionGroupIDs(int userID, public List<Integer> retrieveConnectionGroupIDs(int userID,
String permissionType) { String permissionType) {
// A system administrator has access to all connections. return retrieveConnectionGroupIDs(userID, null, permissionType, false);
if(checkSystemAdministratorAccess(userID))
}
/**
* Find the list of the IDs of all connection groups a user has permission to.
* The access type is defined by permissionType.
*
* @param userID The ID of the user to check.
* @param parentID the parent connection group.
* @param permissionType The type of permission to check for.
* @return A list of all connection group IDs this user has the specified access
* to.
*/
public List<Integer> retrieveConnectionGroupIDs(int userID, Integer parentID,
String permissionType) {
return retrieveConnectionGroupIDs(userID, parentID, permissionType, true);
}
/**
* Find the list of the IDs of all connection groups a user has permission to.
* The access type is defined by permissionType.
*
* @param userID The ID of the user to check.
* @param parentID the parent connection group.
* @param permissionType The type of permission to check for.
* @param checkParentID Whether the parentID should be checked or not.
* @return A list of all connection group IDs this user has the specified access
* to.
*/
private List<Integer> retrieveConnectionGroupIDs(int userID, Integer parentID,
String permissionType, boolean checkParentID) {
// A system administrator has access to all connectionGroups .
if(checkSystemAdministratorAccess(userID)) {
if(checkParentID)
return connectionGroupService.getAllConnectionGroupIDs(parentID);
else
return connectionGroupService.getAllConnectionGroupIDs(); return connectionGroupService.getAllConnectionGroupIDs();
}
// Query all connection permissions for the given user and permission type // Query all connection permissions for the given user and permission type
ConnectionGroupPermissionExample example = new ConnectionGroupPermissionExample(); ConnectionGroupPermissionExample example = new ConnectionGroupPermissionExample();
example.createCriteria().andUser_idEqualTo(userID).andPermissionEqualTo(permissionType); ConnectionGroupPermissionExample.Criteria criteria =
example.createCriteria().andUser_idEqualTo(userID)
.andPermissionEqualTo(permissionType);
// Ensure that the connection groups are all under the parent ID, if needed
if(checkParentID) {
// Get the IDs of all connection groups in the connection group
List<Integer> allConnectionGroupIDs = connectionGroupService
.getAllConnectionGroupIDs(parentID);
criteria.andConnection_group_idIn(allConnectionGroupIDs);
}
example.setDistinct(true); example.setDistinct(true);
List<ConnectionGroupPermissionKey> connectionGroupPermissions = List<ConnectionGroupPermissionKey> connectionGroupPermissions =
connectionGroupPermissionDAO.selectByExample(example); connectionGroupPermissionDAO.selectByExample(example);
@@ -414,24 +577,52 @@ public class PermissionCheckService {
* *
* @param userID The user whose permissions should be checked. * @param userID The user whose permissions should be checked.
* @param permissionType The permission to check. * @param permissionType The permission to check.
* @param parentID The parent connection group.
* @return A set of all connection names for which the given user has the * @return A set of all connection names for which the given user has the
* given permission. * given permission.
*/ */
public Set<String> retrieveConnectionNames(int userID, String permissionType) { public Set<String> retrieveConnectionNames(int userID, Integer parentID,
String permissionType) {
// A system administrator has access to all connections. // A system administrator has access to all connections.
if(checkSystemAdministratorAccess(userID)) if(checkSystemAdministratorAccess(userID))
return connectionService.getAllConnectionNames(); return connectionService.getAllConnectionNames(parentID);
// List of all connection IDs for which this connection has read access // List of all connection IDs for which this user has access
List<Integer> connectionIDs = List<Integer> connectionIDs =
retrieveConnectionIDs(userID, MySQLConstants.CONNECTION_READ); retrieveConnectionIDs(userID, parentID, permissionType);
// Query all associated connections // Query all associated connections
return connectionService.translateNames(connectionIDs).keySet(); return connectionService.translateNames(connectionIDs).keySet();
} }
/**
* Retrieve all existing connection names that the given user has permission
* to perform the given operation upon.
*
* @param userID The user whose permissions should be checked.
* @param permissionType The permission to check.
* @param parentID The parent connection group.
* @return A set of all connection names for which the given user has the
* given permission.
*/
public Set<String> retrieveConnectionGroupNames(int userID, Integer parentID,
String permissionType) {
// A system administrator has access to all connections.
if(checkSystemAdministratorAccess(userID))
return connectionService.getAllConnectionNames(parentID);
// List of all connection group IDs for which this user has access
List<Integer> connectionGroupIDs =
retrieveConnectionGroupIDs(userID, parentID, permissionType);
// Query all associated connections
return connectionGroupService.translateNames(connectionGroupIDs).keySet();
}
/** /**
* Retrieves all user permissions granted to the user having the given ID. * Retrieves all user permissions granted to the user having the given ID.
* *

View File

@@ -47,6 +47,11 @@ import net.sourceforge.guacamole.protocol.GuacamoleConfiguration;
*/ */
public abstract class AbstractConnection implements Connection { public abstract class AbstractConnection implements Connection {
/**
* The name associated with this connection.
*/
private String name;
/** /**
* The unique identifier associated with this connection. * The unique identifier associated with this connection.
*/ */
@@ -57,6 +62,16 @@ public abstract class AbstractConnection implements Connection {
*/ */
private GuacamoleConfiguration configuration; private GuacamoleConfiguration configuration;
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override @Override
public String getIdentifier() { public String getIdentifier() {
return identifier; return identifier;

View File

@@ -45,11 +45,26 @@ package net.sourceforge.guacamole.net.auth;
*/ */
public abstract class AbstractConnectionGroup implements ConnectionGroup { public abstract class AbstractConnectionGroup implements ConnectionGroup {
/**
* The name associated with this connection group.
*/
private String name;
/** /**
* The unique identifier associated with this connection group. * The unique identifier associated with this connection group.
*/ */
private String identifier; private String identifier;
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override @Override
public String getIdentifier() { public String getIdentifier() {
return identifier; return identifier;

View File

@@ -54,6 +54,19 @@ import net.sourceforge.guacamole.protocol.GuacamoleConfiguration;
*/ */
public interface Connection { public interface Connection {
/**
* Returns the name assigned to this Connection.
* @return The name assigned to this Connection.
*/
public String getName();
/**
* Sets the name assigned to this Connection.
*
* @param identifier The name to assign.
*/
public void setName(String name);
/** /**
* Returns the unique identifier assigned to this Connection. * Returns the unique identifier assigned to this Connection.
* @return The unique identifier assigned to this Connection. * @return The unique identifier assigned to this Connection.

View File

@@ -50,6 +50,19 @@ import net.sourceforge.guacamole.protocol.GuacamoleClientInformation;
*/ */
public interface ConnectionGroup { public interface ConnectionGroup {
/**
* Returns the name assigned to this ConnectionGroup.
* @return The name assigned to this ConnectionGroup.
*/
public String getName();
/**
* Sets the name assigned to this ConnectionGroup.
*
* @param identifier The name to assign.
*/
public void setName(String name);
/** /**
* Returns the unique identifier assigned to this ConnectionGroup. * Returns the unique identifier assigned to this ConnectionGroup.
* @return The unique identifier assigned to this ConnectionGroup. * @return The unique identifier assigned to this ConnectionGroup.
@@ -63,6 +76,19 @@ public interface ConnectionGroup {
*/ */
public void setIdentifier(String identifier); public void setIdentifier(String identifier);
/**
* Sets whether this is a balancing ConnectionGroup.
*
* @param balancing whether this is a balancing ConnectionGroup.
*/
public void setBalancing(boolean balancing);
/**
* Returns true if this is a balancing ConnectionGroup, false otherwise.
* @return true if this is a balancing ConnectionGroup, false otherwise.
*/
public boolean isBalancing();
/** /**
* Retrieves a Directory which can be used to view and manipulate * Retrieves a Directory which can be used to view and manipulate
* connections and their configurations, but only as allowed by the * connections and their configurations, but only as allowed by the

View File

@@ -73,13 +73,17 @@ public class SimpleConnection extends AbstractConnection {
* Creates a new SimpleConnection having the given identifier and * Creates a new SimpleConnection having the given identifier and
* GuacamoleConfiguration. * GuacamoleConfiguration.
* *
* @param identifier The identifier to associated with this connection. * @param name The name to associate with this connection.
* @param identifier The identifier to associate with this connection.
* @param config The configuration describing how to connect to this * @param config The configuration describing how to connect to this
* connection. * connection.
*/ */
public SimpleConnection(String identifier, public SimpleConnection(String name, String identifier,
GuacamoleConfiguration config) { GuacamoleConfiguration config) {
// Set name
setName(name);
// Set identifier // Set identifier
setIdentifier(identifier); setIdentifier(identifier);

View File

@@ -76,7 +76,8 @@ public class SimpleConnectionDirectory
// Create connections for each config // Create connections for each config
for (Entry<String, GuacamoleConfiguration> entry : configs.entrySet()) for (Entry<String, GuacamoleConfiguration> entry : configs.entrySet())
connections.put(entry.getKey(), connections.put(entry.getKey(),
new SimpleConnection(entry.getKey(), entry.getValue())); new SimpleConnection(entry.getKey(), entry.getKey(),
entry.getValue()));
} }

View File

@@ -84,4 +84,15 @@ public class SimpleConnectionGroup extends AbstractConnectionGroup {
throw new GuacamoleSecurityException("Permission denied."); throw new GuacamoleSecurityException("Permission denied.");
} }
@Override
public void setBalancing(boolean balancing) {
// All SimpleConnectionGroups are organizational only
}
@Override
public boolean isBalancing() {
// All SimpleConnectionGroups are organizational only
return false;
}
} }