Ticket #263: Clarified permissioning.

This commit is contained in:
James Muehlner
2013-07-29 23:10:56 -07:00
parent dae8307b3f
commit d5c49ff287
7 changed files with 376 additions and 22 deletions

View File

@@ -8,6 +8,8 @@ CREATE TABLE `guacamole_connection_group` (
`connection_group_id` int(11) NOT NULL AUTO_INCREMENT,
`parent_group_id` int(11),
`connection_group_name` varchar(128) NOT NULL,
`type` enum('ORGANIZATIONAL',
'BALANCING') NOT NULL DEFAULT 'ORGANIZATIONAL',
PRIMARY KEY (`connection_group_id`),
UNIQUE KEY `connection_group_name` (`connection_group_name`),
@@ -112,7 +114,6 @@ CREATE TABLE `guacamole_connection_group_permission` (
`user_id` int(11) NOT NULL,
`connection_group_id` int(11) NOT NULL,
`permission` enum('READ',
'EXECUTE',
'UPDATE',
'DELETE',
'ADMINISTER') NOT NULL,

View File

@@ -8,6 +8,9 @@ CREATE TABLE `guacamole_connection_group` (
`connection_group_id` int(11) NOT NULL AUTO_INCREMENT,
`parent_group_id` int(11),
`connection_group_name` varchar(128) NOT NULL,
`type` enum('ORGANIZATIONAL',
'BALANCING') NOT NULL DEFAULT 'ORGANIZATIONAL',
PRIMARY KEY (`connection_group_id`),
UNIQUE KEY `connection_group_name` (`connection_group_name`),
@@ -39,7 +42,6 @@ CREATE TABLE `guacamole_connection_group_permission` (
`user_id` int(11) NOT NULL,
`connection_group_id` int(11) NOT NULL,
`permission` enum('READ',
'EXECUTE',
'UPDATE',
'DELETE',
'ADMINISTER') NOT NULL,

View File

@@ -66,24 +66,18 @@ public class MySQLConnectionGroup extends AbstractConnectionGroup {
/**
* A Directory of connections that have this connection group as a parent.
*/
private Directory<String, Connection> connectionDirectory;
private Directory<String, Connection> connectionDirectory = null;
/**
* A Directory of connection groups that have this connection group as a parent.
*/
private Directory<String, ConnectionGroup> connectionGroupDirectory;
private Directory<String, ConnectionGroup> connectionGroupDirectory = null;
/**
* Service managing connection groups.
*/
@Inject
private ConnectionGroupService connectionGroupService;
/**
* Service for managing connection groups.
*/
//@Inject
//private ConnectionGroupService connectionGroupService;
/**
* Create a default, empty connection group.
@@ -112,35 +106,38 @@ public class MySQLConnectionGroup extends AbstractConnectionGroup {
*
* @param connectionGroupID The ID of the associated database record, if any.
* @param identifier The unique identifier associated with this connection group.
* @param config The GuacamoleConfiguration associated with this connection.
* @param history All ConnectionRecords associated with this connection.
* @param userID The IID of the user who queried this connection.
*/
public void init(Integer connectionGroupID, String identifier,
Directory<String, Connection> connectionDirectory,
Directory<String, ConnectionGroup> connectionGroupDirectory,
int userID) {
public void init(Integer connectionGroupID, String identifier, int userID) {
this.connectionGroupID = connectionGroupID;
setIdentifier(identifier);
this.connectionDirectory = connectionDirectory;
this.connectionGroupDirectory = connectionGroupDirectory;
this.userID = userID;
}
@Override
public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException {
return connectionGroupService.connect(this, info, userID);
}
private void loadConnectionDirectory() {
}
@Override
public Directory<String, Connection> getConnectionDirectory() throws GuacamoleException {
if(connectionDirectory == null)
loadConnectionDirectory();
return connectionDirectory;
}
private void loadConnectionGroupDirectory() {
}
@Override
public Directory<String, ConnectionGroup> getConnectionGroupDirectory() throws GuacamoleException {
if(connectionGroupDirectory == null)
loadConnectionGroupDirectory();
return connectionGroupDirectory;
}

View File

@@ -37,11 +37,24 @@ package net.sourceforge.guacamole.net.auth.mysql.service;
*
* ***** END LICENSE BLOCK ***** */
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.sourceforge.guacamole.net.GuacamoleSocket;
import net.sourceforge.guacamole.net.auth.mysql.MySQLConnectionGroup;
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.ConnectionExample;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroup;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionGroupExample;
import net.sourceforge.guacamole.protocol.GuacamoleClientInformation;
/**
@@ -76,10 +89,82 @@ public class ConnectionGroupService {
@Inject
private Provider<MySQLConnectionGroup> mysqlConnectionGroupProvider;
public GuacamoleSocket connect(MySQLConnectionGroup aThis,
public GuacamoleSocket connect(MySQLConnectionGroup group,
GuacamoleClientInformation info, int userID) {
throw new UnsupportedOperationException("Not yet implemented");
}
//public Collection<MySQLConnection> getConnectionGroupConnections()
/**
* Retrieves a map of all connection group names for the given 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<Integer, String> retrieveNames(Collection<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<Integer, String> names = new HashMap<Integer, String>();
// Get all connection groups having the given IDs
ConnectionGroupExample example = new ConnectionGroupExample();
example.createCriteria().andConnection_group_idIn(Lists.newArrayList(ids));
List<ConnectionGroup> connectionGroups = connectionGroupDAO.selectByExample(example);
// Produce set of names
for (ConnectionGroup connectionGroup : connectionGroups)
names.put(connectionGroup.getConnection_group_id(),
connectionGroup.getConnection_group_name());
return names;
}
/**
* Get the names of all the connection groups defined in the system.
*
* @return A Set of names of all the connection groups defined in the system.
*/
public Set<String> getAllConnectionGroupNames() {
// Set of all present connection group names
Set<String> names = new HashSet<String>();
// Query all connection group names
List<ConnectionGroup> connectionGroups =
connectionGroupDAO.selectByExample(new ConnectionGroupExample());
for (ConnectionGroup connectionGroup : connectionGroups)
names.add(connectionGroup.getConnection_group_name());
return names;
}
/**
* Get the connection group IDs of all the connection groups defined in the system.
*
* @return A list of connection group IDs of all the connection groups defined in the system.
*/
public List<Integer> getAllConnectionGroupIDs() {
// Set of all present connection group IDs
List<Integer> connectionGroupIDs = new ArrayList<Integer>();
// Query all connection IDs
List<ConnectionGroup> connections =
connectionGroupDAO.selectByExample(new ConnectionGroupExample());
for (ConnectionGroup connection : connections)
connectionGroupIDs.add(connection.getConnection_group_id());
return connectionGroupIDs;
}
}

View File

@@ -43,15 +43,19 @@ import java.util.Map;
import java.util.Set;
import net.sourceforge.guacamole.GuacamoleSecurityException;
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.ConnectionPermissionMapper;
import net.sourceforge.guacamole.net.auth.mysql.dao.SystemPermissionMapper;
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.ConnectionGroupPermissionKey;
import net.sourceforge.guacamole.net.auth.mysql.model.ConnectionPermissionExample;
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.SystemPermissionKey;
import net.sourceforge.guacamole.net.auth.mysql.model.UserPermissionExample;
import net.sourceforge.guacamole.net.auth.mysql.model.UserPermissionKey;
import net.sourceforge.guacamole.net.auth.permission.ConnectionGroupPermission;
import net.sourceforge.guacamole.net.auth.permission.ConnectionPermission;
import net.sourceforge.guacamole.net.auth.permission.Permission;
import net.sourceforge.guacamole.net.auth.permission.SystemPermission;
@@ -75,6 +79,12 @@ public class PermissionCheckService {
@Inject
private ConnectionService connectionService;
/**
* Service for accessing connection groups.
*/
@Inject
private ConnectionGroupService connectionGroupService;
/**
* DAO for accessing permissions related to users.
*/
@@ -86,6 +96,12 @@ public class PermissionCheckService {
*/
@Inject
private ConnectionPermissionMapper connectionPermissionDAO;
/**
* DAO for accessing permissions related to connection groups.
*/
@Inject
private ConnectionGroupPermissionMapper connectionGroupPermissionDAO;
/**
* DAO for accessing permissions related to the system as a whole.
@@ -131,6 +147,26 @@ public class PermissionCheckService {
throw new GuacamoleSecurityException("Permission denied.");
}
/**
* Verifies that the user has the specified access to the given connection group.
* If permission is denied, a GuacamoleSecurityException is thrown.
*
* @param userID The ID of the user to check.
* @param affectedConnectionGroupID The connection group that would be affected by the
* operation if permission is granted.
* @param permissionType The type of permission to check for.
* @throws GuacamoleSecurityException If the specified permission is not
* granted.
*/
public void verifyConnectionGroupAccess(int userID, int affectedConnectionGroupID, String permissionType) throws GuacamoleSecurityException {
// If permission does not exist, throw exception
if(!checkConnectionGroupAccess(userID, affectedConnectionGroupID, permissionType))
throw new GuacamoleSecurityException("Permission denied.");
}
/**
* Verifies that the user has the specified access to the system. If
* permission is denied, a GuacamoleSecurityException is thrown.
@@ -195,6 +231,29 @@ public class PermissionCheckService {
}
/**
* Checks whether a user has the specified type of access to the affected
* connection group.
*
* @param userID The ID of the user to check.
* @param affectedConnectionGroupID The connection group that would be affected by the
* operation if permission is granted.
* @param permissionType The type of permission to check for.
* @return true if the specified permission is granted, false otherwise.
*/
public boolean checkConnectionGroupAccess(int userID, Integer affectedConnectionGroupID, String permissionType) {
// A system administrator has full access to everything.
if(checkSystemAdministratorAccess(userID))
return true;
// Check existence of requested permission
ConnectionGroupPermissionExample example = new ConnectionGroupPermissionExample();
example.createCriteria().andUser_idEqualTo(userID).andConnection_group_idEqualTo(affectedConnectionGroupID).andPermissionEqualTo(permissionType);
return connectionGroupPermissionDAO.countByExample(example) > 0;
}
/**
* Checks whether a user has the specified type of access to the system.
*
@@ -293,6 +352,38 @@ public class PermissionCheckService {
}
/**
* 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 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,
String permissionType) {
// A system administrator has access to all connections.
if(checkSystemAdministratorAccess(userID))
return connectionGroupService.getAllConnectionGroupIDs();
// Query all connection permissions for the given user and permission type
ConnectionGroupPermissionExample example = new ConnectionGroupPermissionExample();
example.createCriteria().andUser_idEqualTo(userID).andPermissionEqualTo(permissionType);
example.setDistinct(true);
List<ConnectionGroupPermissionKey> connectionGroupPermissions =
connectionGroupPermissionDAO.selectByExample(example);
// Convert result into list of IDs
List<Integer> connectionGroupIDs = new ArrayList<Integer>(connectionGroupPermissions.size());
for(ConnectionGroupPermissionKey permission : connectionGroupPermissions)
connectionGroupIDs.add(permission.getConnection_group_id());
return connectionGroupIDs;
}
/**
* Retrieve all existing usernames that the given user has permission to
* perform the given operation upon.
@@ -432,6 +523,52 @@ public class PermissionCheckService {
}
/**
* Retrieves all connection group permissions granted to the user having the
* given ID.
*
* @param userID The ID of the user to retrieve permissions of.
* @return A set of all connection group permissions granted to the user having
* the given ID.
*/
public Set<ConnectionGroupPermission> retrieveConnectionGroupPermissions(int userID) {
// Set of all permissions
Set<ConnectionGroupPermission> permissions = new HashSet<ConnectionGroupPermission>();
// Query all connection permissions
ConnectionGroupPermissionExample connectionGroupPermissionExample = new ConnectionGroupPermissionExample();
connectionGroupPermissionExample.createCriteria().andUser_idEqualTo(userID);
List<ConnectionGroupPermissionKey> connectionGroupPermissions =
connectionGroupPermissionDAO.selectByExample(connectionGroupPermissionExample);
// Get list of affected connection IDs
List<Integer> connectionGroupIDs = new ArrayList<Integer>();
for(ConnectionGroupPermissionKey connectionGroupPermission : connectionGroupPermissions)
connectionGroupIDs.add(connectionGroupPermission.getConnection_group_id());
// Get corresponding names
Map<Integer, String> affectedConnectionGroups =
connectionGroupService.retrieveNames(connectionGroupIDs);
// Add connection permissions
for(ConnectionGroupPermissionKey connectionGroupPermission : connectionGroupPermissions) {
// Construct permission from data
ConnectionGroupPermission permission = new ConnectionGroupPermission(
ConnectionGroupPermission.Type.valueOf(connectionGroupPermission.getPermission()),
affectedConnectionGroups.get(connectionGroupPermission.getConnection_group_id())
);
// Add to set
permissions.add(permission);
}
return permissions;
}
/**
* Retrieves all system permissions granted to the user having the
* given ID.
@@ -487,6 +624,9 @@ public class PermissionCheckService {
// Add connection permissions
allPermissions.addAll(retrieveConnectionPermissions(userID));
// add connection group permissions
allPermissions.addAll(retrieveConnectionGroupPermissions(userID));
// Add system permissions
allPermissions.addAll(retrieveSystemPermissions(userID));

View File

@@ -65,6 +65,14 @@
<property name="ignoreQualifiersAtRuntime" value="true"/>
</table>
<table tableName="guacamole_connection_group_permission"
catalog="${guacamole.database.catalog}"
schema="${guacamole.database.schema}"
domainObjectName="ConnectionGroupPermission" >
<property name="useActualColumnNames" value="true"/>
<property name="ignoreQualifiersAtRuntime" value="true"/>
</table>
<table tableName="guacamole_system_permission"
catalog="${guacamole.database.catalog}"
schema="${guacamole.database.schema}"