GUACAMOLE-5: Replace ConnectionGroupRESTService with new resource-driven implementation.

This commit is contained in:
Michael Jumper
2016-07-12 11:41:59 -07:00
parent 06b7887807
commit 71c2b4e4d4
7 changed files with 382 additions and 287 deletions

View File

@@ -29,13 +29,13 @@ import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
import org.aopalliance.intercept.MethodInterceptor;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
import org.apache.guacamole.rest.auth.TokenRESTService;
import org.apache.guacamole.rest.connectiongroup.ConnectionGroupRESTService;
import org.apache.guacamole.rest.activeconnection.ActiveConnectionRESTService;
import org.apache.guacamole.rest.auth.AuthTokenGenerator;
import org.apache.guacamole.rest.auth.AuthenticationService;
import org.apache.guacamole.rest.auth.SecureRandomAuthTokenGenerator;
import org.apache.guacamole.rest.auth.TokenSessionMap;
import org.apache.guacamole.rest.connection.ConnectionModule;
import org.apache.guacamole.rest.connectiongroup.ConnectionGroupModule;
import org.apache.guacamole.rest.history.HistoryRESTService;
import org.apache.guacamole.rest.language.LanguageRESTService;
import org.apache.guacamole.rest.patch.PatchRESTService;
@@ -89,7 +89,6 @@ public class RESTServiceModule extends ServletModule {
// Set up the API endpoints
bind(ActiveConnectionRESTService.class);
bind(ConnectionGroupRESTService.class);
bind(HistoryRESTService.class);
bind(LanguageRESTService.class);
bind(PatchRESTService.class);
@@ -104,6 +103,7 @@ public class RESTServiceModule extends ServletModule {
// Resources below root
install(new ConnectionModule());
install(new ConnectionGroupModule());
// Set up the servlet and JSON mappings
bind(GuiceContainer.class);

View File

@@ -0,0 +1,107 @@
/*
* 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.connectiongroup;
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.GuacamoleException;
import org.apache.guacamole.net.auth.ConnectionGroup;
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.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
* ConnectionGroups.
*
* @author Michael Jumper
*/
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ConnectionGroupDirectoryResource
extends DirectoryResource<ConnectionGroup, APIConnectionGroup> {
/**
* The UserContext associated with the Directory which contains the
* ConnectionGroup exposed by this resource.
*/
private final UserContext userContext;
/**
* The Directory exposed by this resource.
*/
private final Directory<ConnectionGroup> directory;
/**
* A factory which can be used to create instances of resources representing
* ConnectionGroups.
*/
private final DirectoryObjectResourceFactory<ConnectionGroup, APIConnectionGroup> resourceFactory;
/**
* Creates a new ConnectionGroupDirectoryResource which exposes the
* operations and subresources available for the given ConnectionGroup
* Directory.
*
* @param userContext
* The UserContext associated with the given Directory.
*
* @param directory
* The Directory being exposed.
*
* @param translator
* A DirectoryObjectTranslator implementation which handles
* ConnectionGroups.
*
* @param resourceFactory
* A factory which can be used to create instances of resources
* representing ConnectionGroups.
*/
@AssistedInject
public ConnectionGroupDirectoryResource(@Assisted UserContext userContext,
@Assisted Directory<ConnectionGroup> directory,
DirectoryObjectTranslator<ConnectionGroup, APIConnectionGroup> translator,
DirectoryObjectResourceFactory<ConnectionGroup, APIConnectionGroup> resourceFactory) {
super(userContext, directory, translator, resourceFactory);
this.userContext = userContext;
this.directory = directory;
this.resourceFactory = resourceFactory;
}
@Override
public DirectoryObjectResource<ConnectionGroup, APIConnectionGroup>
getObjectResource(String identifier) throws GuacamoleException {
// Use root group if identifier is the standard root identifier
if (identifier != null && identifier.equals(APIConnectionGroup.ROOT_IDENTIFIER))
return resourceFactory.create(userContext, directory,
userContext.getRootConnectionGroup());
return super.getObjectResource(identifier);
}
}

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.connectiongroup;
import com.google.inject.AbstractModule;
import org.apache.guacamole.rest.directory.DirectoryObjectResourceFactory;
import org.apache.guacamole.rest.directory.DirectoryObjectResource;
import org.apache.guacamole.rest.directory.DirectoryResourceFactory;
import com.google.inject.TypeLiteral;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import org.apache.guacamole.net.auth.ConnectionGroup;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
import org.apache.guacamole.rest.directory.DirectoryResource;
/**
* Guice Module which configures injections required for handling
* ConnectionGroup resources via the REST API.
*
* @author Michael Jumper
*/
public class ConnectionGroupModule extends AbstractModule {
@Override
protected void configure() {
// Create the required DirectoryResourceFactory implementation
install(new FactoryModuleBuilder()
.implement(
new TypeLiteral<DirectoryResource<ConnectionGroup, APIConnectionGroup>>() {},
ConnectionGroupDirectoryResource.class
)
.build(new TypeLiteral<DirectoryResourceFactory<ConnectionGroup, APIConnectionGroup>>() {}));
// Create the required DirectoryObjectResourceFactory implementation
install(new FactoryModuleBuilder()
.implement(
new TypeLiteral<DirectoryObjectResource<ConnectionGroup, APIConnectionGroup>>() {},
ConnectionGroupResource.class
)
.build(new TypeLiteral<DirectoryObjectResourceFactory<ConnectionGroup, APIConnectionGroup>>() {}));
// Bind translator for converting between ConnectionGroup and APIConnectionGroup
bind(new TypeLiteral<DirectoryObjectTranslator<ConnectionGroup, APIConnectionGroup>>() {})
.to(ConnectionGroupObjectTranslator.class);
}
}

View File

@@ -0,0 +1,58 @@
/*
* 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.connectiongroup;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.ConnectionGroup;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
/**
* Translator which converts between ConnectionGroup objects and
* APIConnectionGroup objects.
*
* @author Michael Jumper
*/
public class ConnectionGroupObjectTranslator
implements DirectoryObjectTranslator<ConnectionGroup, APIConnectionGroup> {
@Override
public APIConnectionGroup toExternalObject(ConnectionGroup object)
throws GuacamoleException {
return new APIConnectionGroup(object);
}
@Override
public ConnectionGroup toInternalObject(APIConnectionGroup object) {
return new APIConnectionGroupWrapper(object);
}
@Override
public void applyExternalChanges(ConnectionGroup existingObject,
APIConnectionGroup object) {
// Update the connection group
existingObject.setName(object.getName());
existingObject.setParentIdentifier(object.getParentIdentifier());
existingObject.setType(object.getType());
existingObject.setAttributes(object.getAttributes());
}
}

View File

@@ -1,284 +0,0 @@
/*
* 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.connectiongroup;
import com.google.inject.Inject;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.ConnectionGroup;
import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.guacamole.GuacamoleSession;
import org.apache.guacamole.rest.ObjectRetrievalService;
import org.apache.guacamole.rest.auth.AuthenticationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A REST Service for handling connection group CRUD operations.
*
* @author James Muehlner
*/
@Path("/data/{dataSource}/connectionGroups")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ConnectionGroupRESTService {
/**
* Logger for this class.
*/
private static final Logger logger = LoggerFactory.getLogger(ConnectionGroupRESTService.class);
/**
* A service for authenticating users from auth tokens.
*/
@Inject
private AuthenticationService authenticationService;
/**
* Service for convenient retrieval of objects.
*/
@Inject
private ObjectRetrievalService retrievalService;
/**
* Gets an individual connection group.
*
* @param authToken
* The authentication token that is used to authenticate the user
* performing the operation.
*
* @param authProviderIdentifier
* The unique identifier of the AuthenticationProvider associated with
* the UserContext containing the connection group to be retrieved.
*
* @param connectionGroupID
* The ID of the connection group to retrieve.
*
* @return
* The connection group, without any descendants.
*
* @throws GuacamoleException
* If a problem is encountered while retrieving the connection group.
*/
@GET
@Path("/{connectionGroupID}")
public APIConnectionGroup getConnectionGroup(@QueryParam("token") String authToken,
@PathParam("dataSource") String authProviderIdentifier,
@PathParam("connectionGroupID") String connectionGroupID)
throws GuacamoleException {
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
// Retrieve the requested connection group
return new APIConnectionGroup(retrievalService.retrieveConnectionGroup(session, authProviderIdentifier, connectionGroupID));
}
/**
* Gets an individual connection group and all children.
*
* @param authToken
* The authentication token that is used to authenticate the user
* performing the operation.
*
* @param authProviderIdentifier
* The unique identifier of the AuthenticationProvider associated with
* the UserContext containing the connection group to be retrieved.
*
* @param connectionGroupID
* The ID of the connection group to retrieve.
*
* @param permissions
* If specified and non-empty, limit the returned list to only those
* connections for which the current user has any of the given
* permissions. Otherwise, all visible connections are returned.
* Connection groups are unaffected by this parameter.
*
* @return
* The requested connection group, including all descendants.
*
* @throws GuacamoleException
* If a problem is encountered while retrieving the connection group or
* its descendants.
*/
@GET
@Path("/{connectionGroupID}/tree")
public APIConnectionGroup getConnectionGroupTree(@QueryParam("token") String authToken,
@PathParam("dataSource") String authProviderIdentifier,
@PathParam("connectionGroupID") String connectionGroupID,
@QueryParam("permission") List<ObjectPermission.Type> permissions)
throws GuacamoleException {
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
// Retrieve the requested tree, filtering by the given permissions
ConnectionGroup treeRoot = retrievalService.retrieveConnectionGroup(userContext, connectionGroupID);
ConnectionGroupTree tree = new ConnectionGroupTree(userContext, treeRoot, permissions);
// Return tree as a connection group
return tree.getRootAPIConnectionGroup();
}
/**
* Deletes an individual connection group.
*
* @param authToken
* The authentication token that is used to authenticate the user
* performing the operation.
*
* @param authProviderIdentifier
* The unique identifier of the AuthenticationProvider associated with
* the UserContext containing the connection group to be deleted.
*
* @param connectionGroupID
* The identifier of the connection group to delete.
*
* @throws GuacamoleException
* If an error occurs while deleting the connection group.
*/
@DELETE
@Path("/{connectionGroupID}")
public void deleteConnectionGroup(@QueryParam("token") String authToken,
@PathParam("dataSource") String authProviderIdentifier,
@PathParam("connectionGroupID") String connectionGroupID)
throws GuacamoleException {
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
// Get the connection group directory
Directory<ConnectionGroup> connectionGroupDirectory = userContext.getConnectionGroupDirectory();
// Delete the connection group
connectionGroupDirectory.remove(connectionGroupID);
}
/**
* Creates a new connection group and returns the new connection group,
* with identifier field populated.
*
* @param authToken
* The authentication token that is used to authenticate the user
* performing the operation.
*
* @param authProviderIdentifier
* The unique identifier of the AuthenticationProvider associated with
* the UserContext in which the connection group is to be created.
*
* @param connectionGroup
* The connection group to create.
*
* @return
* The new connection group.
*
* @throws GuacamoleException
* If an error occurs while creating the connection group.
*/
@POST
public APIConnectionGroup createConnectionGroup(
@QueryParam("token") String authToken,
@PathParam("dataSource") String authProviderIdentifier,
APIConnectionGroup connectionGroup) throws GuacamoleException {
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
// Validate that connection group data was provided
if (connectionGroup == null)
throw new GuacamoleClientException("Connection group JSON must be submitted when creating connections groups.");
// Add the new connection group
Directory<ConnectionGroup> connectionGroupDirectory = userContext.getConnectionGroupDirectory();
connectionGroupDirectory.add(new APIConnectionGroupWrapper(connectionGroup));
// Return the new connection group
return connectionGroup;
}
/**
* Updates a connection group. If the parent identifier of the
* connection group is changed, the connection group will also be moved to
* the new parent group.
*
* @param authToken
* The authentication token that is used to authenticate the user
* performing the operation.
*
* @param authProviderIdentifier
* The unique identifier of the AuthenticationProvider associated with
* the UserContext containing the connection group to be updated.
*
* @param connectionGroupID
* The identifier of the existing connection group to update.
*
* @param connectionGroup
* The data to update the existing connection group with.
*
* @throws GuacamoleException
* If an error occurs while updating the connection group.
*/
@PUT
@Path("/{connectionGroupID}")
public void updateConnectionGroup(@QueryParam("token") String authToken,
@PathParam("dataSource") String authProviderIdentifier,
@PathParam("connectionGroupID") String connectionGroupID,
APIConnectionGroup connectionGroup)
throws GuacamoleException {
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
// Validate that connection group data was provided
if (connectionGroup == null)
throw new GuacamoleClientException("Connection group JSON must be submitted when updating connection groups.");
// Get the connection group directory
Directory<ConnectionGroup> connectionGroupDirectory = userContext.getConnectionGroupDirectory();
// Retrieve connection group to update
ConnectionGroup existingConnectionGroup = retrievalService.retrieveConnectionGroup(userContext, connectionGroupID);
// Update the connection group
existingConnectionGroup.setName(connectionGroup.getName());
existingConnectionGroup.setParentIdentifier(connectionGroup.getParentIdentifier());
existingConnectionGroup.setType(connectionGroup.getType());
existingConnectionGroup.setAttributes(connectionGroup.getAttributes());
connectionGroupDirectory.update(existingConnectionGroup);
}
}

View File

@@ -0,0 +1,120 @@
/*
* 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.connectiongroup;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.ConnectionGroup;
import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.net.auth.permission.ObjectPermission;
import org.apache.guacamole.rest.directory.DirectoryObjectResource;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
/**
* A REST resource which abstracts the operations available on an existing
* ConnectionGroup.
*
* @author Michael Jumper
*/
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ConnectionGroupResource
extends DirectoryObjectResource<ConnectionGroup, APIConnectionGroup> {
/**
* The UserContext associated with the Directory which contains the
* ConnectionGroup exposed by this resource.
*/
private final UserContext userContext;
/**
* The ConnectionGroup object represented by this ConnectionGroupResource.
*/
private final ConnectionGroup connectionGroup;
/**
* Creates a new ConnectionGroupResource which exposes the operations and
* subresources available for the given ConnectionGroup.
*
* @param userContext
* The UserContext associated with the given Directory.
*
* @param directory
* The Directory which contains the given ConnectionGroup.
*
* @param connectionGroup
* The ConnectionGroup that this ConnectionGroupResource should
* represent.
*
* @param translator
* A DirectoryObjectTranslator implementation which handles the type of
* object given.
*/
@AssistedInject
public ConnectionGroupResource(@Assisted UserContext userContext,
@Assisted Directory<ConnectionGroup> directory,
@Assisted ConnectionGroup connectionGroup,
DirectoryObjectTranslator<ConnectionGroup, APIConnectionGroup> translator) {
super(directory, connectionGroup, translator);
this.userContext = userContext;
this.connectionGroup = connectionGroup;
}
/**
* Returns the current connection group along with all descendants.
*
* @param permissions
* If specified and non-empty, limit the returned list to only those
* connections for which the current user has any of the given
* permissions. Otherwise, all visible connections are returned.
* ConnectionGroups are unaffected by this parameter.
*
* @return
* The current connection group, including all descendants.
*
* @throws GuacamoleException
* If a problem is encountered while retrieving the connection group or
* its descendants.
*/
@GET
@Path("tree")
public APIConnectionGroup getConnectionGroupTree(
@QueryParam("permission") List<ObjectPermission.Type> permissions)
throws GuacamoleException {
// Retrieve the requested tree, filtering by the given permissions
ConnectionGroupTree tree = new ConnectionGroupTree(userContext,
connectionGroup, permissions);
// Return tree as a connection group
return tree.getRootAPIConnectionGroup();
}
}

View File

@@ -30,8 +30,10 @@ import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.ConnectionGroup;
import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.rest.connection.APIConnection;
import org.apache.guacamole.rest.connectiongroup.APIConnectionGroup;
/**
* A REST resource which exposes the contents of a particular UserContext.
@@ -52,7 +54,16 @@ public class UserContextResource {
* Connection Directory.
*/
@Inject
private DirectoryResourceFactory<Connection, APIConnection> connectionDirectoryResourceFactory;
private DirectoryResourceFactory<Connection, APIConnection>
connectionDirectoryResourceFactory;
/**
* Factory for creating DirectoryResources which expose a given
* ConnectionGroup Directory.
*/
@Inject
private DirectoryResourceFactory<ConnectionGroup, APIConnectionGroup>
connectionGroupDirectoryResourceFactory;
/**
* Creates a new UserContextResource which exposes the data within the
@@ -85,4 +96,22 @@ public class UserContextResource {
userContext.getConnectionDirectory());
}
/**
* Returns a new resource which represents the ConnectionGroup Directory
* contained within the UserContext exposed by this UserContextResource.
*
* @return
* A new resource which represents the ConnectionGroup Directory
* contained within the UserContext exposed by this UserContextResource.
*
* @throws GuacamoleException
* If an error occurs while retrieving the ConnectionGroup Directory.
*/
@Path("connectionGroups")
public DirectoryResource<ConnectionGroup, APIConnectionGroup> getConnectionGroupDirectoryResource()
throws GuacamoleException {
return connectionGroupDirectoryResourceFactory.create(userContext,
userContext.getConnectionGroupDirectory());
}
}