GUACAMOLE-220: Expose user groups, group membership, and group permissions via REST.

This commit is contained in:
Michael Jumper
2018-04-19 14:37:26 -07:00
parent 9b99b18041
commit c26cf60e6b
16 changed files with 1029 additions and 30 deletions

View File

@@ -46,6 +46,7 @@ import org.apache.guacamole.rest.sharingprofile.SharingProfileModule;
import org.apache.guacamole.rest.tunnel.TunnelCollectionResourceFactory; import org.apache.guacamole.rest.tunnel.TunnelCollectionResourceFactory;
import org.apache.guacamole.rest.tunnel.TunnelResourceFactory; import org.apache.guacamole.rest.tunnel.TunnelResourceFactory;
import org.apache.guacamole.rest.user.UserModule; import org.apache.guacamole.rest.user.UserModule;
import org.apache.guacamole.rest.usergroup.UserGroupModule;
import org.webjars.servlet.WebjarsServlet; import org.webjars.servlet.WebjarsServlet;
/** /**
@@ -107,6 +108,7 @@ public class RESTServiceModule extends ServletModule {
install(new ConnectionGroupModule()); install(new ConnectionGroupModule());
install(new SharingProfileModule()); install(new SharingProfileModule());
install(new UserModule()); install(new UserModule());
install(new UserGroupModule());
// Set up the servlet and JSON mappings // Set up the servlet and JSON mappings
bind(GuiceContainer.class); bind(GuiceContainer.class);

View File

@@ -0,0 +1,89 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.rest.identifier;
import java.util.HashSet;
import java.util.Set;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.RelatedObjectSet;
/**
* A set of changes to be applied to a RelatedObjectSet, describing the
* objects being added and/or removed.
*/
public class RelatedObjectSetPatch {
/**
* A set containing the identifiers of all objects being added.
*/
private final Set<String> addedObjects = new HashSet<String>();
/**
* A set containing the identifiers of all objects being removed.
*/
private final Set<String> removedObjects = new HashSet<String>();
/**
* Queues the object having the given identifier for addition to the
* underlying RelatedObjectSet. The add operation will be performed only
* when apply() is called.
*
* @param identifier
* The identifier of the object to add.
*/
public void addObject(String identifier) {
addedObjects.add(identifier);
}
/**
* Queues the object having the given identifier for removal from the
* underlying RelatedObjectSet. The remove operation will be performed only
* when apply() is called.
*
* @param identifier
* The identifier of the object to remove.
*/
public void removeObject(String identifier) {
removedObjects.add(identifier);
}
/**
* Applies all queued changes to the given RelatedObjectSet.
*
* @param objects
* The RelatedObjectSet to add and/or remove objects from.
*
* @throws GuacamoleException
* If any add or remove operation is disallowed by the underlying
* RelatedObjectSet.
*/
public void apply(RelatedObjectSet objects) throws GuacamoleException {
// Add any added identifiers
if (!addedObjects.isEmpty())
objects.addObjects(addedObjects);
// Remove any removed identifiers
if (!removedObjects.isEmpty())
objects.removeObjects(removedObjects);
}
}

View File

@@ -0,0 +1,164 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.rest.identifier;
import java.util.List;
import java.util.Set;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.RelatedObjectSet;
import org.apache.guacamole.rest.APIPatch;
import org.apache.guacamole.rest.PATCH;
/**
* A REST resource which abstracts the operations available on arbitrary sets
* of objects which share some common relation.
*/
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class RelatedObjectSetResource {
/**
* The path of any operation within a JSON patch which adds/removes an
* object from the associated set.
*/
private static final String OBJECT_PATH = "/";
/**
* The set of objects represented by this RelatedObjectSetResource.
*/
private final RelatedObjectSet objects;
/**
* Creates a new RelatedObjectSetResource which exposes the operations and
* subresources available for the given RelatedObjectSet.
*
* @param objects
* The RelatedObjectSet exposed by this RelatedObjectSetResource.
*/
public RelatedObjectSetResource(RelatedObjectSet objects) {
this.objects = objects;
}
/**
* Returns the identifiers of all objects within RelatedObjectSet exposed by
* this RelatedObjectSetResource.
*
* @return
* The identifiers of all objects within RelatedObjectSet exposed by
* this RelatedObjectSetResource.
*
* @throws GuacamoleException
* If an error occurs while retrieving the objects within the set, or
* if objects cannot be retrieved due to lack of permissions to do so.
*/
@GET
public Set<String> getObjects() throws GuacamoleException {
return objects.getObjects();
}
/**
* Updates the given RelatedObjectSetPatch by queuing an add or remove
* operation for the object having the given identifier based on the given
* patch operation.
*
* @param operation
* The patch operation to perform.
*
* @param relatedObjectSetPatch
* The RelatedObjectSetPatch being modified.
*
* @param identifier
* The identifier of the object being added or removed from the set.
*
* @throws GuacamoleException
* If the requested patch operation is not supported.
*/
private void updateRelatedObjectSet(APIPatch.Operation operation,
RelatedObjectSetPatch relatedObjectSetPatch, String identifier)
throws GuacamoleException {
// Add or remove object based on operation
switch (operation) {
// Add object
case add:
relatedObjectSetPatch.addObject(identifier);
break;
// Remove object
case remove:
relatedObjectSetPatch.removeObject(identifier);
break;
// Unsupported patch operation
default:
throw new GuacamoleClientException("Unsupported patch operation: \"" + operation + "\"");
}
}
/**
* Applies a given list of patches to the RelatedObjectSet exposed by this
* RelatedObjectSetResource. Each patch specifies either
* an "add" or a "remove" operation for a particular object represented
* by its identifier. The path of each operation MUST be "/", with the
* identifier of the object being provided within the value of the patch.
*
* @param patches
* The patches to apply for this request.
*
* @throws GuacamoleException
* If an error is encountered while modifying the contents of the
* RelatedObjectSet.
*/
@PATCH
public void patchObjects(List<APIPatch<String>> patches)
throws GuacamoleException {
// Apply all patch operations individually
RelatedObjectSetPatch objectPatch = new RelatedObjectSetPatch();
for (APIPatch<String> patch : patches) {
String path = patch.getPath();
// Add/remove objects from set
if (path.equals(OBJECT_PATH)) {
String identifier = patch.getValue();
updateRelatedObjectSet(patch.getOp(), objectPatch, identifier);
}
// Otherwise, the path is not supported
else
throw new GuacamoleClientException("Unsupported patch path: \"" + path + "\"");
} // end for each patch operation
// Save changes
objectPatch.apply(objects);
}
}

View File

@@ -0,0 +1,24 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* Classes related to manipulating arbitrary sets of unique identifiers using
* the Guacamole REST API.
*/
package org.apache.guacamole.rest.identifier;

View File

@@ -71,6 +71,12 @@ public class APIPermissionSet {
private Map<String, Set<ObjectPermission.Type>> userPermissions = private Map<String, Set<ObjectPermission.Type>> userPermissions =
new HashMap<String, Set<ObjectPermission.Type>>(); new HashMap<String, Set<ObjectPermission.Type>>();
/**
* Map of user group ID to the set of granted permissions.
*/
private Map<String, Set<ObjectPermission.Type>> userGroupPermissions =
new HashMap<String, Set<ObjectPermission.Type>>();
/** /**
* Set of all granted system-level permissions. * Set of all granted system-level permissions.
*/ */
@@ -163,6 +169,7 @@ public class APIPermissionSet {
addObjectPermissions(sharingProfilePermissions, permissions.getSharingProfilePermissions()); addObjectPermissions(sharingProfilePermissions, permissions.getSharingProfilePermissions());
addObjectPermissions(activeConnectionPermissions, permissions.getActiveConnectionPermissions()); addObjectPermissions(activeConnectionPermissions, permissions.getActiveConnectionPermissions());
addObjectPermissions(userPermissions, permissions.getUserPermissions()); addObjectPermissions(userPermissions, permissions.getUserPermissions());
addObjectPermissions(userGroupPermissions, permissions.getUserGroupPermissions());
} }
@@ -239,6 +246,20 @@ public class APIPermissionSet {
return userPermissions; return userPermissions;
} }
/**
* Returns a map of user group IDs to the set of permissions granted for
* that user group. If no permissions are granted for a particular user
* group, its ID will not be present as a key in the map. This map is
* mutable, and changes to to this map will affect the permission set
* directly.
*
* @return
* A map of user IDs to the set of permissions granted for that user.
*/
public Map<String, Set<ObjectPermission.Type>> getUserGroupPermissions() {
return userGroupPermissions;
}
/** /**
* Returns the set of granted system-level permissions. If no permissions * Returns the set of granted system-level permissions. If no permissions
* are granted at the system level, this will be an empty set. This set is * are granted at the system level, this will be an empty set. This set is
@@ -316,6 +337,19 @@ public class APIPermissionSet {
this.userPermissions = userPermissions; this.userPermissions = userPermissions;
} }
/**
* Replaces the current map of user group permissions with the given map,
* which must map user group ID to its corresponding set of granted
* permissions. If a user group has no permissions, its ID must not be
* present as a key in the map.
*
* @param userGroupPermissions
* The map which must replace the currently-stored map of permissions.
*/
public void setUserGroupPermissions(Map<String, Set<ObjectPermission.Type>> userGroupPermissions) {
this.userGroupPermissions = userGroupPermissions;
}
/** /**
* Replaces the current set of system-level permissions with the given set. * Replaces the current set of system-level permissions with the given set.
* If no system-level permissions are granted, the empty set must be * If no system-level permissions are granted, the empty set must be

View File

@@ -26,7 +26,7 @@ import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleClientException; import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.User; import org.apache.guacamole.net.auth.Permissions;
import org.apache.guacamole.net.auth.permission.ObjectPermission; import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.guacamole.net.auth.permission.Permission; import org.apache.guacamole.net.auth.permission.Permission;
import org.apache.guacamole.net.auth.permission.SystemPermission; import org.apache.guacamole.net.auth.permission.SystemPermission;
@@ -35,78 +35,88 @@ import org.apache.guacamole.rest.PATCH;
/** /**
* A REST resource which abstracts the operations available on the permissions * A REST resource which abstracts the operations available on the permissions
* granted to an existing User. * granted to an existing User or UserGroup.
*/ */
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
public class PermissionSetResource { public class PermissionSetResource {
/** /**
* The prefix of any path within an operation of a JSON patch which * The prefix of any path within an operation of a JSON patch which modifies
* modifies the permissions of a user regarding a specific connection. * the permissions of a user or user group regarding a specific connection.
*/ */
private static final String CONNECTION_PERMISSION_PATCH_PATH_PREFIX = "/connectionPermissions/"; private static final String CONNECTION_PERMISSION_PATCH_PATH_PREFIX = "/connectionPermissions/";
/** /**
* The prefix of any path within an operation of a JSON patch which * The prefix of any path within an operation of a JSON patch which modifies
* modifies the permissions of a user regarding a specific connection group. * the permissions of a user or user group regarding a specific connection
* group.
*/ */
private static final String CONNECTION_GROUP_PERMISSION_PATCH_PATH_PREFIX = "/connectionGroupPermissions/"; private static final String CONNECTION_GROUP_PERMISSION_PATCH_PATH_PREFIX = "/connectionGroupPermissions/";
/** /**
* The prefix of any path within an operation of a JSON patch which * The prefix of any path within an operation of a JSON patch which modifies
* modifies the permissions of a user regarding a specific sharing profile. * the permissions of a user or user group regarding a specific sharing
* profile.
*/ */
private static final String SHARING_PROFILE_PERMISSION_PATCH_PATH_PREFIX = "/sharingProfilePermissions/"; private static final String SHARING_PROFILE_PERMISSION_PATCH_PATH_PREFIX = "/sharingProfilePermissions/";
/** /**
* The prefix of any path within an operation of a JSON patch which * The prefix of any path within an operation of a JSON patch which modifies
* modifies the permissions of a user regarding a specific active connection. * the permissions of a user or user group regarding a specific active
* connection.
*/ */
private static final String ACTIVE_CONNECTION_PERMISSION_PATCH_PATH_PREFIX = "/activeConnectionPermissions/"; private static final String ACTIVE_CONNECTION_PERMISSION_PATCH_PATH_PREFIX = "/activeConnectionPermissions/";
/** /**
* The prefix of any path within an operation of a JSON patch which * The prefix of any path within an operation of a JSON patch which modifies
* modifies the permissions of a user regarding another, specific user. * the permissions of a user or user group regarding a specific user.
*/ */
private static final String USER_PERMISSION_PATCH_PATH_PREFIX = "/userPermissions/"; private static final String USER_PERMISSION_PATCH_PATH_PREFIX = "/userPermissions/";
/**
* The prefix of any path within an operation of a JSON patch which modifies
* the permissions of a user or user group regarding a specific user group.
*/
private static final String USER_GROUP_PERMISSION_PATCH_PATH_PREFIX = "/userGroupPermissions/";
/** /**
* The path of any operation within a JSON patch which modifies the * The path of any operation within a JSON patch which modifies the
* permissions of a user regarding the entire system. * permissions of a user or user group regarding the entire system.
*/ */
private static final String SYSTEM_PERMISSION_PATCH_PATH = "/systemPermissions"; private static final String SYSTEM_PERMISSION_PATCH_PATH = "/systemPermissions";
/** /**
* The User object whose permissions are represented by this * The permissions represented by this PermissionSetResource.
* PermissionSetResource.
*/ */
private final User user; private final Permissions permissions;
/** /**
* Creates a new PermissionSetResource which exposes the operations and * Creates a new PermissionSetResource which exposes the operations and
* subresources available for permissions of the given User. * subresources available for the given Permissions object.
* *
* @param user * @param permissions
* The User whose permissions should be represented by this * The permissions that should be represented by this
* PermissionSetResource. * PermissionSetResource.
*/ */
public PermissionSetResource(User user) { public PermissionSetResource(Permissions permissions) {
this.user = user; this.permissions = permissions;
} }
/** /**
* Gets a list of permissions for the user with the given username. * Gets a list of all permissions granted to the user or user group
* associated with this PermissionSetResource.
* *
* @return * @return
* A list of all permissions granted to the specified user. * A list of all permissions granted to the user or user group
* associated with this PermissionSetResource.
* *
* @throws GuacamoleException * @throws GuacamoleException
* If an error occurs while retrieving permissions. * If an error occurs while retrieving permissions.
*/ */
@GET @GET
public APIPermissionSet getPermissions() throws GuacamoleException { public APIPermissionSet getPermissions() throws GuacamoleException {
return new APIPermissionSet(user); return new APIPermissionSet(permissions);
} }
/** /**
@@ -177,6 +187,7 @@ public class PermissionSetResource {
PermissionSetPatch<ObjectPermission> sharingProfilePermissionPatch = new PermissionSetPatch<ObjectPermission>(); PermissionSetPatch<ObjectPermission> sharingProfilePermissionPatch = new PermissionSetPatch<ObjectPermission>();
PermissionSetPatch<ObjectPermission> activeConnectionPermissionPatch = new PermissionSetPatch<ObjectPermission>(); PermissionSetPatch<ObjectPermission> activeConnectionPermissionPatch = new PermissionSetPatch<ObjectPermission>();
PermissionSetPatch<ObjectPermission> userPermissionPatch = new PermissionSetPatch<ObjectPermission>(); PermissionSetPatch<ObjectPermission> userPermissionPatch = new PermissionSetPatch<ObjectPermission>();
PermissionSetPatch<ObjectPermission> userGroupPermissionPatch = new PermissionSetPatch<ObjectPermission>();
PermissionSetPatch<SystemPermission> systemPermissionPatch = new PermissionSetPatch<SystemPermission>(); PermissionSetPatch<SystemPermission> systemPermissionPatch = new PermissionSetPatch<SystemPermission>();
// Apply all patch operations individually // Apply all patch operations individually
@@ -249,6 +260,19 @@ public class PermissionSetResource {
} }
// Create user group permission if path has user group prefix
else if (path.startsWith(USER_GROUP_PERMISSION_PATCH_PATH_PREFIX)) {
// Get identifier and type from patch operation
String identifier = path.substring(USER_GROUP_PERMISSION_PATCH_PATH_PREFIX.length());
ObjectPermission.Type type = ObjectPermission.Type.valueOf(patch.getValue());
// Create and update corresponding permission
ObjectPermission permission = new ObjectPermission(type, identifier);
updatePermissionSet(patch.getOp(), userGroupPermissionPatch, permission);
}
// Create system permission if path is system path // Create system permission if path is system path
else if (path.equals(SYSTEM_PERMISSION_PATCH_PATH)) { else if (path.equals(SYSTEM_PERMISSION_PATCH_PATH)) {
@@ -268,12 +292,13 @@ public class PermissionSetResource {
} // end for each patch operation } // end for each patch operation
// Save the permission changes // Save the permission changes
connectionPermissionPatch.apply(user.getConnectionPermissions()); connectionPermissionPatch.apply(permissions.getConnectionPermissions());
connectionGroupPermissionPatch.apply(user.getConnectionGroupPermissions()); connectionGroupPermissionPatch.apply(permissions.getConnectionGroupPermissions());
sharingProfilePermissionPatch.apply(user.getSharingProfilePermissions()); sharingProfilePermissionPatch.apply(permissions.getSharingProfilePermissions());
activeConnectionPermissionPatch.apply(user.getActiveConnectionPermissions()); activeConnectionPermissionPatch.apply(permissions.getActiveConnectionPermissions());
userPermissionPatch.apply(user.getUserPermissions()); userPermissionPatch.apply(permissions.getUserPermissions());
systemPermissionPatch.apply(user.getSystemPermissions()); userGroupPermissionPatch.apply(permissions.getUserGroupPermissions());
systemPermissionPatch.apply(permissions.getSystemPermissions());
} }

View File

@@ -77,6 +77,25 @@ public class SchemaResource {
} }
/**
* Retrieves the possible attributes of a user group object.
*
* @return
* A collection of forms which describe the possible attributes of a
* user group object.
*
* @throws GuacamoleException
* If an error occurs while retrieving the possible attributes.
*/
@GET
@Path("userGroupAttributes")
public Collection<Form> getUserGroupAttributes() throws GuacamoleException {
// Retrieve all possible user group attributes
return userContext.getUserGroupAttributes();
}
/** /**
* Retrieves the possible attributes of a connection object. * Retrieves the possible attributes of a connection object.
* *

View File

@@ -35,6 +35,7 @@ import org.apache.guacamole.net.auth.ConnectionGroup;
import org.apache.guacamole.net.auth.SharingProfile; import org.apache.guacamole.net.auth.SharingProfile;
import org.apache.guacamole.net.auth.User; import org.apache.guacamole.net.auth.User;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.net.auth.UserGroup;
import org.apache.guacamole.rest.activeconnection.APIActiveConnection; import org.apache.guacamole.rest.activeconnection.APIActiveConnection;
import org.apache.guacamole.rest.connection.APIConnection; import org.apache.guacamole.rest.connection.APIConnection;
import org.apache.guacamole.rest.connectiongroup.APIConnectionGroup; import org.apache.guacamole.rest.connectiongroup.APIConnectionGroup;
@@ -44,6 +45,7 @@ import org.apache.guacamole.rest.history.HistoryResource;
import org.apache.guacamole.rest.schema.SchemaResource; import org.apache.guacamole.rest.schema.SchemaResource;
import org.apache.guacamole.rest.sharingprofile.APISharingProfile; import org.apache.guacamole.rest.sharingprofile.APISharingProfile;
import org.apache.guacamole.rest.user.APIUser; import org.apache.guacamole.rest.user.APIUser;
import org.apache.guacamole.rest.usergroup.APIUserGroup;
/** /**
* A REST resource which exposes the contents of a particular UserContext. * A REST resource which exposes the contents of a particular UserContext.
@@ -102,6 +104,13 @@ public class UserContextResource {
@Inject @Inject
private DirectoryResourceFactory<User, APIUser> userDirectoryResourceFactory; private DirectoryResourceFactory<User, APIUser> userDirectoryResourceFactory;
/**
* Factory for creating DirectoryResources which expose a given
* UserGroup Directory.
*/
@Inject
private DirectoryResourceFactory<UserGroup, APIUserGroup> userGroupDirectoryResourceFactory;
/** /**
* Creates a new UserContextResource which exposes the data within the * Creates a new UserContextResource which exposes the data within the
* given UserContext. * given UserContext.
@@ -225,6 +234,24 @@ public class UserContextResource {
userContext.getUserDirectory()); userContext.getUserDirectory());
} }
/**
* Returns a new resource which represents the UserGroup Directory contained
* within the UserContext exposed by this UserContextResource.
*
* @return
* A new resource which represents the UserGroup Directory contained
* within the UserContext exposed by this UserContextResource.
*
* @throws GuacamoleException
* If an error occurs while retrieving the UserGroup Directory.
*/
@Path("userGroups")
public DirectoryResource<UserGroup, APIUserGroup> getUserGroupDirectoryResource()
throws GuacamoleException {
return userGroupDirectoryResourceFactory.create(userContext,
userContext.getUserGroupDirectory());
}
/** /**
* Returns a new resource which represents historical data contained * Returns a new resource which represents historical data contained
* within the UserContext exposed by this UserContextResource. * within the UserContext exposed by this UserContextResource.

View File

@@ -43,6 +43,7 @@ import org.apache.guacamole.net.auth.credentials.GuacamoleCredentialsException;
import org.apache.guacamole.rest.directory.DirectoryObjectResource; import org.apache.guacamole.rest.directory.DirectoryObjectResource;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator; import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
import org.apache.guacamole.rest.history.APIActivityRecord; import org.apache.guacamole.rest.history.APIActivityRecord;
import org.apache.guacamole.rest.identifier.RelatedObjectSetResource;
import org.apache.guacamole.rest.permission.APIPermissionSet; import org.apache.guacamole.rest.permission.APIPermissionSet;
import org.apache.guacamole.rest.permission.PermissionSetResource; import org.apache.guacamole.rest.permission.PermissionSetResource;
@@ -211,4 +212,21 @@ public class UserResource
return new APIPermissionSet(user.getEffectivePermissions()); return new APIPermissionSet(user.getEffectivePermissions());
} }
/**
* Returns a resource which abstracts operations available on the set of
* user groups of which the User represented by this UserResource is a
* member.
*
* @return
* A resource which represents the set of user groups of which the
* User represented by this UserResource is a member.
*
* @throws GuacamoleException
* If the group membership for this user cannot be retrieved.
*/
@Path("userGroups")
public RelatedObjectSetResource getUserGroups() throws GuacamoleException {
return new RelatedObjectSetResource(user.getUserGroups());
}
} }

View File

@@ -0,0 +1,106 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.rest.usergroup;
import java.util.Map;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.apache.guacamole.net.auth.UserGroup;
/**
* A simple UserGroup to expose through the REST endpoints.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
public class APIUserGroup {
/**
* The identifier of this user group.
*/
private String identifier;
/**
* Map of all associated attributes by attribute identifier.
*/
private Map<String, String> attributes;
/**
* Construct a new empty APIUserGroup.
*/
public APIUserGroup() {}
/**
* Construct a new APIUserGroup from the provided UserGroup.
*
* @param group
* The UserGroup to construct the APIUserGroup from.
*/
public APIUserGroup(UserGroup group) {
this.identifier = group.getIdentifier();
this.attributes = group.getAttributes();
}
/**
* Returns the unique string which identifies this group relative to other
* groups.
*
* @return
* The unique string which identifies this group.
*/
public String getIdentifier() {
return identifier;
}
/**
* Sets the unique string which identifies this group relative to other
* groups.
*
* @param identifier
* The unique string which identifies this group.
*/
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
/**
* Returns a map of all attributes associated with this user group. Each
* entry key is the attribute identifier, while each value is the attribute
* value itself.
*
* @return
* The attribute map for this user group.
*/
public Map<String, String> getAttributes() {
return attributes;
}
/**
* Sets the map of all attributes associated with this user group. Each
* entry key is the attribute identifier, while each value is the attribute
* value itself.
*
* @param attributes
* The attribute map for this user group.
*/
public void setAttributes(Map<String, String> attributes) {
this.attributes = attributes;
}
}

View File

@@ -0,0 +1,131 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.rest.usergroup;
import java.util.Map;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.net.auth.RelatedObjectSet;
import org.apache.guacamole.net.auth.UserGroup;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
/**
* A wrapper to make an APIUserGroup look like a UserGroup. Useful where an
* org.apache.guacamole.net.auth.UserGroup is required. As a simple wrapper for
* APIUserGroup, access to permissions, groups, and members is not provided.
* Any attempt to access or manipulate permissions or group membership via an
* APIUserGroupWrapper will result in an exception.
*/
public class APIUserGroupWrapper implements UserGroup {
/**
* The wrapped APIUserGroup.
*/
private final APIUserGroup apiUserGroup;
/**
* Creates a new APIUserGroupWrapper which wraps the given APIUserGroup,
* exposing its properties through the UserGroup interface.
*
* @param apiUserGroup
* The APIUserGroup to wrap.
*/
public APIUserGroupWrapper(APIUserGroup apiUserGroup) {
this.apiUserGroup = apiUserGroup;
}
@Override
public String getIdentifier() {
return apiUserGroup.getIdentifier();
}
@Override
public void setIdentifier(String identifier) {
apiUserGroup.setIdentifier(identifier);
}
@Override
public Map<String, String> getAttributes() {
return apiUserGroup.getAttributes();
}
@Override
public void setAttributes(Map<String, String> attributes) {
apiUserGroup.setAttributes(attributes);
}
@Override
public SystemPermissionSet getSystemPermissions()
throws GuacamoleException {
throw new GuacamoleUnsupportedException("APIUserGroupWrapper does not provide permission access.");
}
@Override
public ObjectPermissionSet getConnectionPermissions()
throws GuacamoleException {
throw new GuacamoleUnsupportedException("APIUserGroupWrapper does not provide permission access.");
}
@Override
public ObjectPermissionSet getConnectionGroupPermissions()
throws GuacamoleException {
throw new GuacamoleUnsupportedException("APIUserGroupWrapper does not provide permission access.");
}
@Override
public ObjectPermissionSet getSharingProfilePermissions() throws GuacamoleException {
throw new GuacamoleUnsupportedException("APIUserGroupWrapper does not provide permission access.");
}
@Override
public ObjectPermissionSet getUserPermissions()
throws GuacamoleException {
throw new GuacamoleUnsupportedException("APIUserGroupWrapper does not provide permission access.");
}
@Override
public ObjectPermissionSet getUserGroupPermissions()
throws GuacamoleException {
throw new GuacamoleUnsupportedException("APIUserGroupWrapper does not provide permission access.");
}
@Override
public ObjectPermissionSet getActiveConnectionPermissions()
throws GuacamoleException {
throw new GuacamoleUnsupportedException("APIUserGroupWrapper does not provide permission access.");
}
@Override
public RelatedObjectSet getUserGroups() throws GuacamoleException {
throw new GuacamoleUnsupportedException("APIUserGroupWrapper does not provide group access.");
}
@Override
public RelatedObjectSet getMemberUsers() throws GuacamoleException {
throw new GuacamoleUnsupportedException("APIUserGroupWrapper does not provide member access.");
}
@Override
public RelatedObjectSet getMemberUserGroups() throws GuacamoleException {
throw new GuacamoleUnsupportedException("APIUserGroupWrapper does not provide member access.");
}
}

View File

@@ -0,0 +1,68 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.rest.usergroup;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.guacamole.net.auth.UserGroup;
import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.rest.directory.DirectoryObjectResourceFactory;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
import org.apache.guacamole.rest.directory.DirectoryResource;
/**
* A REST resource which abstracts the operations available on a Directory of
* UserGroups.
*/
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class UserGroupDirectoryResource extends DirectoryResource<UserGroup, APIUserGroup> {
/**
* Creates a new UserGroupDirectoryResource which exposes the operations
* and subresources available for the given UserGroup Directory.
*
* @param userContext
* The UserContext associated with the given Directory.
*
* @param directory
* The Directory being exposed.
*
* @param translator
* A DirectoryObjectTranslator implementation which handles
* UserGroups.
*
* @param resourceFactory
* A factory which can be used to create instances of resources
* representing UserGroups.
*/
@AssistedInject
public UserGroupDirectoryResource(@Assisted UserContext userContext,
@Assisted Directory<UserGroup> directory,
DirectoryObjectTranslator<UserGroup, APIUserGroup> translator,
DirectoryObjectResourceFactory<UserGroup, APIUserGroup> resourceFactory) {
super(userContext, directory, translator, resourceFactory);
}
}

View File

@@ -0,0 +1,63 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.rest.usergroup;
import com.google.inject.AbstractModule;
import org.apache.guacamole.rest.directory.DirectoryObjectResourceFactory;
import org.apache.guacamole.rest.directory.DirectoryResourceFactory;
import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import org.apache.guacamole.net.auth.UserGroup;
import org.apache.guacamole.rest.directory.DirectoryObjectResource;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
import org.apache.guacamole.rest.directory.DirectoryResource;
/**
* Guice Module which configures injections required for handling UserGroup
* resources via the REST API.
*/
public class UserGroupModule extends AbstractModule {
@Override
protected void configure() {
// Create the required DirectoryResourceFactory implementation
install(new FactoryModuleBuilder()
.implement(
new TypeLiteral<DirectoryResource<UserGroup, APIUserGroup>>() {},
UserGroupDirectoryResource.class
)
.build(new TypeLiteral<DirectoryResourceFactory<UserGroup, APIUserGroup>>() {}));
// Create the required DirectoryObjectResourceFactory implementation
install(new FactoryModuleBuilder()
.implement(
new TypeLiteral<DirectoryObjectResource<UserGroup, APIUserGroup>>() {},
UserGroupResource.class
)
.build(new TypeLiteral<DirectoryObjectResourceFactory<UserGroup, APIUserGroup>>() {}));
// Bind translator for converting between UserGroup and APIUserGroup
bind(new TypeLiteral<DirectoryObjectTranslator<UserGroup, APIUserGroup>>() {})
.to(UserGroupObjectTranslator.class);
}
}

View File

@@ -0,0 +1,65 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.rest.usergroup;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.net.auth.UserGroup;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
/**
* Translator which converts between UserGroup objects and APIUserGroup
* objects.
*/
public class UserGroupObjectTranslator
extends DirectoryObjectTranslator<UserGroup, APIUserGroup> {
@Override
public APIUserGroup toExternalObject(UserGroup object)
throws GuacamoleException {
return new APIUserGroup(object);
}
@Override
public UserGroup toInternalObject(APIUserGroup object)
throws GuacamoleException {
return new APIUserGroupWrapper(object);
}
@Override
public void applyExternalChanges(UserGroup existingObject,
APIUserGroup object) throws GuacamoleException {
// Update user attributes
existingObject.setAttributes(object.getAttributes());
}
@Override
public void filterExternalObject(UserContext userContext, APIUserGroup object)
throws GuacamoleException {
// Filter object attributes by defined schema
object.setAttributes(filterAttributes(userContext.getUserAttributes(),
object.getAttributes()));
}
}

View File

@@ -0,0 +1,141 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.rest.usergroup;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import javax.ws.rs.Consumes;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.UserGroup;
import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.rest.directory.DirectoryObjectResource;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
import org.apache.guacamole.rest.identifier.RelatedObjectSetResource;
import org.apache.guacamole.rest.permission.PermissionSetResource;
/**
* A REST resource which abstracts the operations available on an existing
* UserGroup.
*/
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class UserGroupResource
extends DirectoryObjectResource<UserGroup, APIUserGroup> {
/**
* The UserGroup object represented by this UserGroupResource.
*/
private final UserGroup userGroup;
/**
* Creates a new UserGroupResource which exposes the operations and
* subresources available for the given UserGroup.
*
* @param userContext
* The UserContext associated with the given Directory.
*
* @param directory
* The Directory which contains the given UserGroup.
*
* @param userGroup
* The UserGroup that this UserGroupResource should represent.
*
* @param translator
* A DirectoryObjectTranslator implementation which handles Users.
*/
@AssistedInject
public UserGroupResource(@Assisted UserContext userContext,
@Assisted Directory<UserGroup> directory,
@Assisted UserGroup userGroup,
DirectoryObjectTranslator<UserGroup, APIUserGroup> translator) {
super(userContext, directory, userGroup, translator);
this.userGroup = userGroup;
}
/**
* Returns a resource which abstracts operations available on the set of
* user groups of which the UserGroup represented by this UserGroupResource
* is a member.
*
* @return
* A resource which represents the set of user groups of which the
* UserGroup represented by this UserGroupResource is a member.
*
* @throws GuacamoleException
* If the group membership for this user group cannot be retrieved.
*/
@Path("userGroups")
public RelatedObjectSetResource getUserGroups() throws GuacamoleException {
return new RelatedObjectSetResource(userGroup.getUserGroups());
}
/**
* Returns a resource which abstracts operations available on the set of
* users which are members of the UserGroup represented by this
* UserGroupResource.
*
* @return
* A resource which represents the set of users which are members of
* the UserGroup represented by this UserGroupResource.
*
* @throws GuacamoleException
* If the members of this user group cannot be retrieved.
*/
@Path("memberUsers")
public RelatedObjectSetResource getMemberUsers() throws GuacamoleException {
return new RelatedObjectSetResource(userGroup.getMemberUsers());
}
/**
* Returns a resource which abstracts operations available on the set of
* user groups which are members of the UserGroup represented by this
* UserGroupResource.
*
* @return
* A resource which represents the set of user groups which are
* members of the UserGroup represented by this UserGroupResource.
*
* @throws GuacamoleException
* If the members of this user group cannot be retrieved.
*/
@Path("memberUserGroups")
public RelatedObjectSetResource getMemberUserGroups() throws GuacamoleException {
return new RelatedObjectSetResource(userGroup.getMemberUserGroups());
}
/**
* Returns a resource which abstracts operations available on the overall
* permissions granted directly to the UserGroup represented by this
* UserGroupResource.
*
* @return
* A resource which represents the permissions granted to the
* UserGroup represented by this UserGroupResource.
*/
@Path("permissions")
public PermissionSetResource getPermissions() {
return new PermissionSetResource(userGroup);
}
}

View File

@@ -0,0 +1,23 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* Classes related to manipulating user groups via the Guacamole REST API.
*/
package org.apache.guacamole.rest.usergroup;