GUACAMOLE-81: Generalize permissions surrounding parent/child relationship.

This commit is contained in:
Michael Jumper
2016-08-20 18:03:32 -07:00
parent 39a25db594
commit 26d9dd8593
9 changed files with 88 additions and 54 deletions

View File

@@ -20,12 +20,13 @@
package org.apache.guacamole.auth.jdbc.base; package org.apache.guacamole.auth.jdbc.base;
/** /**
* Object representation of a Guacamole object, such as a user or connection, * Object representation of a Guacamole object which can be the child of another
* as represented in the database. * object, such as a connection or sharing profile, as represented in the
* database.
* *
* @author Michael Jumper * @author Michael Jumper
*/ */
public abstract class GroupedObjectModel extends ObjectModel { public abstract class ChildObjectModel extends ObjectModel {
/** /**
* The unique identifier which identifies the parent of this object. * The unique identifier which identifies the parent of this object.
@@ -35,7 +36,7 @@ public abstract class GroupedObjectModel extends ObjectModel {
/** /**
* Creates a new, empty object. * Creates a new, empty object.
*/ */
public GroupedObjectModel() { public ChildObjectModel() {
} }
/** /**

View File

@@ -30,7 +30,7 @@ import org.apache.guacamole.auth.jdbc.connectiongroup.RootConnectionGroup;
* @param <ModelType> * @param <ModelType>
* The type of model object that corresponds to this object. * The type of model object that corresponds to this object.
*/ */
public abstract class ModeledGroupedDirectoryObject<ModelType extends GroupedObjectModel> public abstract class ModeledChildDirectoryObject<ModelType extends ChildObjectModel>
extends ModeledDirectoryObject<ModelType> { extends ModeledDirectoryObject<ModelType> {
/** /**

View File

@@ -31,7 +31,7 @@ import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
/** /**
* Service which provides convenience methods for creating, retrieving, and * Service which provides convenience methods for creating, retrieving, and
* manipulating objects that can be within connection groups. This service will * manipulating objects that can be children of other objects. This service will
* automatically enforce the permissions of the current user. * automatically enforce the permissions of the current user.
* *
* @author Michael Jumper * @author Michael Jumper
@@ -47,15 +47,33 @@ import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
* The underlying model object used to represent InternalType in the * The underlying model object used to represent InternalType in the
* database. * database.
*/ */
public abstract class ModeledGroupedDirectoryObjectService<InternalType extends ModeledGroupedDirectoryObject<ModelType>, public abstract class ModeledChildDirectoryObjectService<InternalType extends ModeledChildDirectoryObject<ModelType>,
ExternalType extends Identifiable, ModelType extends GroupedObjectModel> ExternalType extends Identifiable, ModelType extends ChildObjectModel>
extends ModeledDirectoryObjectService<InternalType, ExternalType, ModelType> { extends ModeledDirectoryObjectService<InternalType, ExternalType, ModelType> {
/** /**
* Returns the set of parent connection groups that are modified by the * Returns the permission set associated with the given user and related
* given model object (by virtue of the object changing parent groups). If * to the type of objects which can be parents of the child objects handled
* the model is not changing parents, the resulting collection will be * by this directory object service.
* empty. *
* @param user
* The user whose permissions are being retrieved.
*
* @return
* A permission set which contains the permissions associated with the
* given user and related to the type of objects which can be parents
* of the child objects handled by this directory object service.
*
* @throws GuacamoleException
* If permission to read the user's permissions is denied.
*/
protected abstract ObjectPermissionSet getParentPermissionSet(
ModeledAuthenticatedUser user) throws GuacamoleException;
/**
* Returns the set of parent objects that are modified by the given model
* object (by virtue of the object changing parents). If the model is not
* changing parents, the resulting collection will be empty.
* *
* @param user * @param user
* The user making the given changes to the model. * The user making the given changes to the model.
@@ -69,14 +87,13 @@ public abstract class ModeledGroupedDirectoryObjectService<InternalType extends
* deleted, this will be null. * deleted, this will be null.
* *
* @return * @return
* A collection of the identifiers of all parent connection groups * A collection of the identifiers of all parents that will be affected
* that will be affected (updated) by the change. * (updated) by the change.
* *
* @throws GuacamoleException * @throws GuacamoleException
* If an error occurs while determining which parent connection groups * If an error occurs while determining which parents are affected.
* are affected.
*/ */
protected Collection<String> getModifiedGroups(ModeledAuthenticatedUser user, protected Collection<String> getModifiedParents(ModeledAuthenticatedUser user,
String identifier, ModelType model) throws GuacamoleException { String identifier, ModelType model) throws GuacamoleException {
// Get old parent identifier // Get old parent identifier
@@ -98,18 +115,17 @@ public abstract class ModeledGroupedDirectoryObjectService<InternalType extends
} }
// Return collection of all non-root groups involved // Return collection of all non-root parents involved
Collection<String> groups = new ArrayList<String>(2); Collection<String> parents = new ArrayList<String>(2);
if (oldParentIdentifier != null) groups.add(oldParentIdentifier); if (oldParentIdentifier != null) parents.add(oldParentIdentifier);
if (parentIdentifier != null) groups.add(parentIdentifier); if (parentIdentifier != null) parents.add(parentIdentifier);
return groups; return parents;
} }
/** /**
* Returns whether the given user has permission to modify the parent * Returns whether the given user has permission to modify the parents
* connection groups affected by the modifications made to the given model * affected by the modifications made to the given model object.
* object.
* *
* @param user * @param user
* The user who changed the model object. * The user who changed the model object.
@@ -123,31 +139,30 @@ public abstract class ModeledGroupedDirectoryObjectService<InternalType extends
* deleted, this will be null. * deleted, this will be null.
* *
* @return * @return
* true if the user has update permission for all modified groups, * true if the user has update permission for all modified parents,
* false otherwise. * false otherwise.
* *
* @throws GuacamoleException * @throws GuacamoleException
* If an error occurs while determining which parent connection groups * If an error occurs while determining which parents are affected.
* are affected.
*/ */
protected boolean canUpdateModifiedGroups(ModeledAuthenticatedUser user, protected boolean canUpdateModifiedParents(ModeledAuthenticatedUser user,
String identifier, ModelType model) throws GuacamoleException { String identifier, ModelType model) throws GuacamoleException {
// If user is an administrator, no need to check // If user is an administrator, no need to check
if (user.getUser().isAdministrator()) if (user.getUser().isAdministrator())
return true; return true;
// Verify that we have permission to modify any modified groups // Verify that we have permission to modify any modified parents
Collection<String> modifiedGroups = getModifiedGroups(user, identifier, model); Collection<String> modifiedParents = getModifiedParents(user, identifier, model);
if (!modifiedGroups.isEmpty()) { if (!modifiedParents.isEmpty()) {
ObjectPermissionSet permissionSet = user.getUser().getConnectionGroupPermissions(); ObjectPermissionSet permissionSet = getParentPermissionSet(user);
Collection<String> updateableGroups = permissionSet.getAccessibleObjects( Collection<String> updateableParents = permissionSet.getAccessibleObjects(
Collections.singleton(ObjectPermission.Type.UPDATE), Collections.singleton(ObjectPermission.Type.UPDATE),
modifiedGroups modifiedParents
); );
return updateableGroups.size() == modifiedGroups.size(); return updateableParents.size() == modifiedParents.size();
} }
@@ -161,8 +176,8 @@ public abstract class ModeledGroupedDirectoryObjectService<InternalType extends
super.beforeCreate(user, model); super.beforeCreate(user, model);
// Validate that we can update all applicable parent groups // Validate that we can update all applicable parents
if (!canUpdateModifiedGroups(user, null, model)) if (!canUpdateModifiedParents(user, null, model))
throw new GuacamoleSecurityException("Permission denied."); throw new GuacamoleSecurityException("Permission denied.");
} }
@@ -173,8 +188,8 @@ public abstract class ModeledGroupedDirectoryObjectService<InternalType extends
super.beforeUpdate(user, model); super.beforeUpdate(user, model);
// Validate that we can update all applicable parent groups // Validate that we can update all applicable parents
if (!canUpdateModifiedGroups(user, model.getIdentifier(), model)) if (!canUpdateModifiedParents(user, model.getIdentifier(), model))
throw new GuacamoleSecurityException("Permission denied."); throw new GuacamoleSecurityException("Permission denied.");
} }
@@ -185,8 +200,8 @@ public abstract class ModeledGroupedDirectoryObjectService<InternalType extends
super.beforeDelete(user, identifier); super.beforeDelete(user, identifier);
// Validate that we can update all applicable parent groups // Validate that we can update all applicable parents
if (!canUpdateModifiedGroups(user, identifier, null)) if (!canUpdateModifiedParents(user, identifier, null))
throw new GuacamoleSecurityException("Permission denied."); throw new GuacamoleSecurityException("Permission denied.");
} }

View File

@@ -21,7 +21,7 @@ package org.apache.guacamole.auth.jdbc.connection;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.apache.guacamole.auth.jdbc.base.GroupedObjectModel; import org.apache.guacamole.auth.jdbc.base.ChildObjectModel;
/** /**
* Object representation of a Guacamole connection, as represented in the * Object representation of a Guacamole connection, as represented in the
@@ -29,7 +29,7 @@ import org.apache.guacamole.auth.jdbc.base.GroupedObjectModel;
* *
* @author Michael Jumper * @author Michael Jumper
*/ */
public class ConnectionModel extends GroupedObjectModel { public class ConnectionModel extends ChildObjectModel {
/** /**
* The human-readable name associated with this connection. * The human-readable name associated with this connection.

View File

@@ -34,7 +34,7 @@ import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
import org.apache.guacamole.GuacamoleClientException; import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.auth.jdbc.base.ModeledGroupedDirectoryObjectService; import org.apache.guacamole.auth.jdbc.base.ModeledChildDirectoryObjectService;
import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionMapper; import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionMapper;
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper; import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
import org.apache.guacamole.net.GuacamoleTunnel; import org.apache.guacamole.net.GuacamoleTunnel;
@@ -52,7 +52,7 @@ import org.apache.guacamole.protocol.GuacamoleClientInformation;
* *
* @author Michael Jumper, James Muehlner * @author Michael Jumper, James Muehlner
*/ */
public class ConnectionService extends ModeledGroupedDirectoryObjectService<ModeledConnection, Connection, ConnectionModel> { public class ConnectionService extends ModeledChildDirectoryObjectService<ModeledConnection, Connection, ConnectionModel> {
/** /**
* Mapper for accessing connections. * Mapper for accessing connections.
@@ -145,6 +145,15 @@ public class ConnectionService extends ModeledGroupedDirectoryObjectService<Mode
} }
@Override
protected ObjectPermissionSet getParentPermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException {
// Connections are contained by connection groups
return user.getUser().getConnectionGroupPermissions();
}
@Override @Override
protected void beforeCreate(ModeledAuthenticatedUser user, protected void beforeCreate(ModeledAuthenticatedUser user,
ConnectionModel model) throws GuacamoleException { ConnectionModel model) throws GuacamoleException {

View File

@@ -31,7 +31,7 @@ import java.util.Set;
import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService; import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.JDBCEnvironment; import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
import org.apache.guacamole.auth.jdbc.base.ModeledGroupedDirectoryObject; import org.apache.guacamole.auth.jdbc.base.ModeledChildDirectoryObject;
import org.apache.guacamole.form.Field; import org.apache.guacamole.form.Field;
import org.apache.guacamole.form.Form; import org.apache.guacamole.form.Form;
import org.apache.guacamole.form.NumericField; import org.apache.guacamole.form.NumericField;
@@ -50,7 +50,7 @@ import org.slf4j.LoggerFactory;
* @author James Muehlner * @author James Muehlner
* @author Michael Jumper * @author Michael Jumper
*/ */
public class ModeledConnection extends ModeledGroupedDirectoryObject<ConnectionModel> public class ModeledConnection extends ModeledChildDirectoryObject<ConnectionModel>
implements Connection { implements Connection {
/** /**

View File

@@ -21,7 +21,7 @@ package org.apache.guacamole.auth.jdbc.connectiongroup;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import org.apache.guacamole.auth.jdbc.base.GroupedObjectModel; import org.apache.guacamole.auth.jdbc.base.ChildObjectModel;
import org.apache.guacamole.net.auth.ConnectionGroup; import org.apache.guacamole.net.auth.ConnectionGroup;
/** /**
@@ -30,7 +30,7 @@ import org.apache.guacamole.net.auth.ConnectionGroup;
* *
* @author Michael Jumper * @author Michael Jumper
*/ */
public class ConnectionGroupModel extends GroupedObjectModel { public class ConnectionGroupModel extends ChildObjectModel {
/** /**
* The human-readable name associated with this connection group. * The human-readable name associated with this connection group.

View File

@@ -29,7 +29,7 @@ import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.GuacamoleUnsupportedException; import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.auth.jdbc.base.ModeledGroupedDirectoryObjectService; import org.apache.guacamole.auth.jdbc.base.ModeledChildDirectoryObjectService;
import org.apache.guacamole.auth.jdbc.permission.ConnectionGroupPermissionMapper; import org.apache.guacamole.auth.jdbc.permission.ConnectionGroupPermissionMapper;
import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper; import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
import org.apache.guacamole.net.GuacamoleTunnel; import org.apache.guacamole.net.GuacamoleTunnel;
@@ -46,7 +46,7 @@ import org.apache.guacamole.protocol.GuacamoleClientInformation;
* *
* @author Michael Jumper, James Muehlner * @author Michael Jumper, James Muehlner
*/ */
public class ConnectionGroupService extends ModeledGroupedDirectoryObjectService<ModeledConnectionGroup, public class ConnectionGroupService extends ModeledChildDirectoryObjectService<ModeledConnectionGroup,
ConnectionGroup, ConnectionGroupModel> { ConnectionGroup, ConnectionGroupModel> {
/** /**
@@ -128,6 +128,15 @@ public class ConnectionGroupService extends ModeledGroupedDirectoryObjectService
} }
@Override
protected ObjectPermissionSet getParentPermissionSet(ModeledAuthenticatedUser user)
throws GuacamoleException {
// Connection groups are contained by other connection groups
return user.getUser().getConnectionGroupPermissions();
}
@Override @Override
protected void beforeCreate(ModeledAuthenticatedUser user, protected void beforeCreate(ModeledAuthenticatedUser user,
ConnectionGroupModel model) throws GuacamoleException { ConnectionGroupModel model) throws GuacamoleException {

View File

@@ -28,7 +28,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.jdbc.JDBCEnvironment; import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
import org.apache.guacamole.auth.jdbc.base.ModeledGroupedDirectoryObject; import org.apache.guacamole.auth.jdbc.base.ModeledChildDirectoryObject;
import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService; import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
import org.apache.guacamole.form.BooleanField; import org.apache.guacamole.form.BooleanField;
import org.apache.guacamole.form.Field; import org.apache.guacamole.form.Field;
@@ -47,7 +47,7 @@ import org.slf4j.LoggerFactory;
* @author James Muehlner * @author James Muehlner
* @author Michael Jumper * @author Michael Jumper
*/ */
public class ModeledConnectionGroup extends ModeledGroupedDirectoryObject<ConnectionGroupModel> public class ModeledConnectionGroup extends ModeledChildDirectoryObject<ConnectionGroupModel>
implements ConnectionGroup { implements ConnectionGroup {
/** /**