Ticket #362: Merge REST changes to master.

This commit is contained in:
James Muehlner
2013-12-19 17:39:52 -08:00
41 changed files with 3031 additions and 2 deletions

View File

@@ -180,6 +180,9 @@ public class ConnectionDirectory implements Directory<String, Connection>{
// Create connection // Create connection
MySQLConnection connection = connectionService.createConnection( MySQLConnection connection = connectionService.createConnection(
name, object.getConfiguration().getProtocol(), user_id, parentID); name, object.getConfiguration().getProtocol(), user_id, parentID);
// Set the connection ID
object.setIdentifier(connection.getIdentifier());
// Add connection parameters // Add connection parameters
createConfigurationValues(connection.getConnectionID(), createConfigurationValues(connection.getConnectionID(),

View File

@@ -168,6 +168,9 @@ public class ConnectionGroupDirectory implements Directory<String, ConnectionGro
// Create connection group // Create connection group
MySQLConnectionGroup connectionGroup = connectionGroupService MySQLConnectionGroup connectionGroup = connectionGroupService
.createConnectionGroup(name, user_id, parentID, mySQLType); .createConnectionGroup(name, user_id, parentID, mySQLType);
// Set the connection group ID
object.setIdentifier(connectionGroup.getIdentifier());
// Finally, give the current user full access to the newly created // Finally, give the current user full access to the newly created
// connection group. // connection group.

View File

@@ -150,6 +150,9 @@ public class UserDirectory implements Directory<String, User> {
// Get user // Get user
MySQLUser user = userService.retrieveUser(identifier); MySQLUser user = userService.retrieveUser(identifier);
if(user == null)
return null;
// Verify access is granted // Verify access is granted
permissionCheckService.verifyUserAccess(this.user_id, permissionCheckService.verifyUserAccess(this.user_id,
@@ -157,7 +160,7 @@ public class UserDirectory implements Directory<String, User> {
MySQLConstants.USER_READ); MySQLConstants.USER_READ);
// Return user // Return user
return userService.retrieveUser(identifier); return user;
} }

View File

@@ -348,7 +348,7 @@ public class ConnectionGroupService {
} }
/** /**
* Creates a new connection group having the given name and protocol. * Creates a new connection group having the given name and type.
* *
* @param name The name to assign to the new connection group. * @param name The name to assign to the new connection group.
* @param userID The ID of the user who created this connection group. * @param userID The ID of the user who created this connection group.

View File

@@ -0,0 +1,67 @@
package org.glyptodon.guacamole.properties;
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is guacamole-ext.
*
* The Initial Developer of the Original Code is
* Michael Jumper.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.GuacamoleServerException;
/**
* A GuacamoleProperty whose value is an long.
*
* @author James Muehlner
*/
public abstract class LongGuacamoleProperty implements GuacamoleProperty<Long> {
@Override
public Long parseValue(String value) throws GuacamoleException {
// If no property provided, return null.
if (value == null)
return null;
try {
Long longValue = new Long(value);
return longValue;
}
catch (NumberFormatException e) {
throw new GuacamoleServerException("Property \"" + getName() + "\" must be an long.", e);
}
}
}

View File

@@ -110,6 +110,55 @@
<version>1.6.1</version> <version>1.6.1</version>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
<!-- Guice - Dependency Injection -->
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
</dependency>
<!-- Guice Servlet -->
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-servlet</artifactId>
<version>3.0</version>
</dependency>
<!-- Jersey - JAX-RS Implementation -->
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>1.17.1</version>
</dependency>
<!-- Jersey - Guice extension -->
<dependency>
<groupId>com.sun.jersey.contribs</groupId>
<artifactId>jersey-guice</artifactId>
<version>1.17.1</version>
</dependency>
<!-- JSR-250 annotations -->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<version>1.0</version>
</dependency>
<!-- Apache commons codec library -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.4</version>
</dependency>
<!-- Jackson for JSON support -->
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.17.1</version>
</dependency>
<!-- Guacamole Java API --> <!-- Guacamole Java API -->
<dependency> <dependency>

View File

@@ -20,6 +20,7 @@ package org.glyptodon.guacamole.net.basic.properties;
*/ */
import org.glyptodon.guacamole.properties.FileGuacamoleProperty; import org.glyptodon.guacamole.properties.FileGuacamoleProperty;
import org.glyptodon.guacamole.properties.LongGuacamoleProperty;
/** /**
* Properties used by the default Guacamole web application. * Properties used by the default Guacamole web application.
@@ -64,4 +65,14 @@ public class BasicGuacamoleProperties {
}; };
/**
* The session timeout for the API, in milliseconds.
*/
public static final LongGuacamoleProperty API_SESSION_TIMEOUT = new LongGuacamoleProperty() {
@Override
public String getName() { return "api-session-timeout"; }
};
} }

View File

@@ -0,0 +1,47 @@
package org.glyptodon.guacamole.net.basic.rest;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* A simple object to represent an error to be sent from the REST API.
* @author James Muehlner
*/
public class APIError {
/**
* The error message.
*/
private String message;
/**
* Get the error message.
* @return The error message.
*/
public String getMessage() {
return message;
}
/**
* Create a new APIError with the specified error message.
* @param message The error message.
*/
public APIError(String message) {
this.message = message;
}
}

View File

@@ -0,0 +1,54 @@
package org.glyptodon.guacamole.net.basic.rest;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
/**
* An exception that will result in the given HTTP Status and message or entity
* being returned from the API layer.
*
* @author James Muehlner
*/
public class HTTPException extends WebApplicationException {
/**
* Construct a new HTTPException with the given HTTP status and entity.
*
* @param status The HTTP Status to use for the response.
* @param entity The entity to use as the body of the response.
*/
public HTTPException(Status status, Object entity) {
super(Response.status(status).entity(entity).build());
}
/**
* Construct a new HTTPException with the given HTTP status and message. The
* message will be wrapped in an APIError container.
*
* @param status The HTTP Status to use for the response.
* @param entity The entity to wrap in an APIError as the body of the response.
*/
public HTTPException(Status status, String message) {
super(Response.status(status).entity(new APIError(message)).build());
}
}

View File

@@ -0,0 +1,79 @@
package org.glyptodon.guacamole.net.basic.rest;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import com.google.inject.AbstractModule;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
import org.glyptodon.guacamole.net.basic.properties.BasicGuacamoleProperties;
import org.glyptodon.guacamole.net.basic.rest.auth.AuthTokenGenerator;
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
import org.glyptodon.guacamole.net.basic.rest.auth.BasicTokenUserContextMap;
import org.glyptodon.guacamole.net.basic.rest.auth.SecureRandomAuthTokenGenerator;
import org.glyptodon.guacamole.net.basic.rest.auth.TokenUserContextMap;
import org.glyptodon.guacamole.net.basic.rest.connection.ConnectionService;
import org.glyptodon.guacamole.net.basic.rest.connectiongroup.ConnectionGroupService;
import org.glyptodon.guacamole.net.basic.rest.permission.PermissionService;
import org.glyptodon.guacamole.net.basic.rest.user.UserService;
import org.glyptodon.guacamole.properties.GuacamoleProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A Guice Module for setting up dependency injection for the
* Guacamole REST API.
*
* @author James Muehlner
*/
public class RESTModule extends AbstractModule {
/**
* Logger for this class.
*/
private static final Logger logger = LoggerFactory.getLogger(RESTModule.class);
/**
* The AuthenticationProvider to use to authenticate all requests.
*/
private AuthenticationProvider authProvider;
@Override
protected void configure() {
// Get auth provider instance
try {
authProvider = GuacamoleProperties.getRequiredProperty(BasicGuacamoleProperties.AUTH_PROVIDER);
}
catch (GuacamoleException e) {
logger.error("Error getting authentication provider from properties.", e);
throw new RuntimeException(e);
}
bind(AuthenticationProvider.class).toInstance(authProvider);
bind(TokenUserContextMap.class).toInstance(new BasicTokenUserContextMap());
bind(ConnectionService.class);
bind(ConnectionGroupService.class);
bind(PermissionService.class);
bind(UserService.class);
bind(AuthenticationService.class);
bind(AuthTokenGenerator.class).to(SecureRandomAuthTokenGenerator.class);
}
}

View File

@@ -0,0 +1,44 @@
package org.glyptodon.guacamole.net.basic.rest;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import com.google.inject.Guice;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* A ServletContextListenr to listen for initialization of the servlet context
* in order to set up the REST services.
*
* @author James Muehlner
*/
public class RESTServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
Guice.createInjector(
new RESTServletModule(),
new RESTModule()
);
}
@Override
public void contextDestroyed(ServletContextEvent sce) {}
}

View File

@@ -0,0 +1,54 @@
package org.glyptodon.guacamole.net.basic.rest;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import com.google.inject.Scopes;
import com.google.inject.servlet.ServletModule;
import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
import org.glyptodon.guacamole.net.basic.rest.auth.LoginRESTService;
import org.glyptodon.guacamole.net.basic.rest.connection.ConnectionRESTService;
import org.glyptodon.guacamole.net.basic.rest.connectiongroup.ConnectionGroupRESTService;
import org.glyptodon.guacamole.net.basic.rest.permission.PermissionRESTService;
import org.glyptodon.guacamole.net.basic.rest.user.UserRESTService;
/**
* A Guice Module to set up the servlet mappings for the Guacamole REST API.
*
* @author James Muehlner
*/
public class RESTServletModule extends ServletModule {
@Override
protected void configureServlets() {
// Set up the API endpoints
bind(ConnectionRESTService.class);
bind(ConnectionGroupRESTService.class);
bind(PermissionRESTService.class);
bind(UserRESTService.class);
bind(LoginRESTService.class);
// Set up the servlet and JSON mappings
bind(GuiceContainer.class);
bind(JacksonJsonProvider.class).in(Scopes.SINGLETON);
serve("/*").with(GuiceContainer.class);
}
}

View File

@@ -0,0 +1,49 @@
package org.glyptodon.guacamole.net.basic.rest.auth;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* A simple object to represent an auth token in the API.
*
* @author James Muehlner
*/
public class APIAuthToken {
/**
* The auth token.
*/
private String authToken;
/**
* Get the auth token.
* @return The auth token.
*/
public String getAuthToken() {
return authToken;
}
/**
* Create a new APIAuthToken Object with the given auth token.
*
* @param authToken The auth token to create the new APIAuthToken with.
*/
public APIAuthToken(String authToken) {
this.authToken = authToken;
}
}

View File

@@ -0,0 +1,34 @@
package org.glyptodon.guacamole.net.basic.rest.auth;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* Generates an auth token for an authenticated user.
*
* @author James Muehlner
*/
public interface AuthTokenGenerator {
/**
* Get a new auth token.
*
* @return A new auth token.
*/
public String getToken();
}

View File

@@ -0,0 +1,62 @@
package org.glyptodon.guacamole.net.basic.rest.auth;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import com.google.inject.Inject;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response.Status;
import org.glyptodon.guacamole.net.auth.UserContext;
import org.glyptodon.guacamole.net.basic.rest.HTTPException;
/**
* A service for performing authentication checks in REST endpoints.
*
* @author James Muehlner
*/
public class AuthenticationService {
/**
* The map of auth tokens to users for the REST endpoints.
*/
@Inject
private TokenUserContextMap tokenUserMap;
/**
* Finds the UserContext for a given auth token, if the auth token represents
* a currently logged in user. Throws an unauthorized error otherwise.
*
* @param authToken The auth token to check against the map of logged in users.
* @return The userContext that corresponds to the provided auth token.
* @throws WebApplicationException If the auth token does not correspond to
* any logged in user.
*/
public UserContext getUserContextFromAuthToken(String authToken)
throws WebApplicationException {
// Try to get the userContext from the map of logged in users.
UserContext userContext = tokenUserMap.get(authToken);
// Authentication failed.
if(userContext == null)
throw new HTTPException(Status.UNAUTHORIZED, "Permission Denied.");
return userContext;
}
}

View File

@@ -0,0 +1,135 @@
package org.glyptodon.guacamole.net.basic.rest.auth;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.UserContext;
import org.glyptodon.guacamole.net.basic.properties.BasicGuacamoleProperties;
import org.glyptodon.guacamole.properties.GuacamoleProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A basic, HashMap-based implementation of the TokenUserContextMap with support
* for session timeouts.
*
* @author James Muehlner
*/
public class BasicTokenUserContextMap implements TokenUserContextMap {
/**
* Logger for this class.
*/
private static Logger logger = LoggerFactory.getLogger(BasicTokenUserContextMap.class);
/**
* The last time a user with a specific auth token accessed the API.
*/
private Map<String, Long> lastAccessTimeMap = new HashMap<String, Long>();
/**
* Keeps track of the authToken to UserContext mapping.
*/
private Map<String, UserContext> userContextMap = new HashMap<String, UserContext>();
/**
* The session timeout configuration for an API session, in milliseconds.
*/
private final long SESSION_TIMEOUT;
/**
* Create a new BasicTokenUserContextMap and initialize the session timeout value.
*/
public BasicTokenUserContextMap() {
// Set up the SESSION_TIMEOUT value, with a one hour default.
long sessionTimeoutValue;
try {
sessionTimeoutValue = GuacamoleProperties.getProperty(BasicGuacamoleProperties.API_SESSION_TIMEOUT, 3600000l);
}
catch (GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught while reading API_SESSION_TIMEOUT property. Defaulting to 1 hour.", e);
sessionTimeoutValue = 3600000l;
}
SESSION_TIMEOUT = sessionTimeoutValue;
}
/**
* Evict an authentication token from the map of logged in users and last
* access times.
*
* @param authToken The authentication token to evict.
*/
private void evict(String authToken) {
userContextMap.remove(authToken);
lastAccessTimeMap.remove(authToken);
}
/**
* Log that the user represented by this auth token has just used the API.
*
* @param authToken The authentication token to record access time for.
*/
private void logAccessTime(String authToken) {
lastAccessTimeMap.put(authToken, new Date().getTime());
}
/**
* Check if a session has timed out.
* @param authToken The auth token for the session.
* @return True if the session has timed out, false otherwise.
*/
private boolean sessionHasTimedOut(String authToken) {
if(!lastAccessTimeMap.containsKey(authToken))
return true;
long lastAccessTime = lastAccessTimeMap.get(authToken);
long currentTime = new Date().getTime();
return currentTime - lastAccessTime > SESSION_TIMEOUT;
}
@Override
public UserContext get(String authToken) {
// If the session has timed out, evict the token and force the user to log in again
if(sessionHasTimedOut(authToken)) {
evict(authToken);
return null;
}
// Update the last access time and return the UserContext
logAccessTime(authToken);
return userContextMap.get(authToken);
}
@Override
public void put(String authToken, UserContext userContext) {
// Update the last access time, and create the token/UserContext mapping
logAccessTime(authToken);
userContextMap.put(authToken, userContext);
}
}

View File

@@ -0,0 +1,109 @@
package org.glyptodon.guacamole.net.basic.rest.auth;
import com.google.inject.Inject;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response.Status;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.AuthenticationProvider;
import org.glyptodon.guacamole.net.auth.Credentials;
import org.glyptodon.guacamole.net.auth.UserContext;
import org.glyptodon.guacamole.net.basic.rest.HTTPException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* A service for authenticating to the Guacamole REST API. Given valid
* credentials, the service will return an auth token. Invalid credentials will
* result in a permission error.
*
* @author James Muehlner
*/
@Path("/api/login")
@Produces(MediaType.APPLICATION_JSON)
public class LoginRESTService {
/**
* The authentication provider used to authenticate this user.
*/
@Inject
private AuthenticationProvider authProvider;
/**
* The map of auth tokens to users for the REST endpoints.
*/
@Inject
private TokenUserContextMap tokenUserMap;
/**
* A generator for creating new auth tokens.
*/
@Inject
private AuthTokenGenerator authTokenGenerator;
/**
* Logger for this class.
*/
private static final Logger logger = LoggerFactory.getLogger(LoginRESTService.class);
/**
* Authenticates a user, generates an auth token, associates that auth token
* with the user's UserContext for use by further requests.
*
* @param username The username of the user who is to be authenticated.
* @param password The password of the user who is to be authenticated.
* @return The auth token for the newly logged-in user.
*/
@POST
public APIAuthToken login(@QueryParam("username") String username,
@QueryParam("password") String password) {
Credentials credentials = new Credentials();
credentials.setUsername(username);
credentials.setPassword(password);
UserContext userContext;
try {
userContext = authProvider.getUserContext(credentials);
} catch(GuacamoleException e) {
logger.error("Exception caught while authenticating user.", e);
throw new HTTPException(Status.INTERNAL_SERVER_ERROR,
"Unexpected server error.");
}
// authentication failed.
if(userContext == null)
throw new HTTPException(Status.UNAUTHORIZED, "Permission Denied.");
String authToken = authTokenGenerator.getToken();
tokenUserMap.put(authToken, userContext);
return new APIAuthToken(authToken);
}
}

View File

@@ -0,0 +1,44 @@
package org.glyptodon.guacamole.net.basic.rest.auth;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import java.security.SecureRandom;
import org.apache.commons.codec.binary.Hex;
/**
* An implementation of the AuthTokenGenerator based around SecureRandom.
*
* @author James Muehlner
*/
public class SecureRandomAuthTokenGenerator implements AuthTokenGenerator {
/**
* Instance of SecureRandom for generating the auth token.
*/
private SecureRandom secureRandom = new SecureRandom();
@Override
public String getToken() {
byte[] bytes = new byte[32];
secureRandom.nextBytes(bytes);
return Hex.encodeHexString(bytes);
}
}

View File

@@ -0,0 +1,49 @@
package org.glyptodon.guacamole.net.basic.rest.auth;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import org.glyptodon.guacamole.net.auth.UserContext;
/**
* Represents a mapping of auth token to user context for the REST
* authentication system.
*
* @author James Muehlner
*/
public interface TokenUserContextMap {
/**
* Registers that a user has just logged in with the specified authToken and
* UserContext.
*
* @param authToken The authentication token for the logged in user.
* @param userContext The UserContext for the logged in user.
*/
public void put(String authToken, UserContext userContext);
/**
* Get the UserContext for a logged in user. If the auth token does not
* represent a user who is currently logged in, returns null.
*
* @param authToken The authentication token for the logged in user.
* @return The UserContext for the given auth token, if the auth token
* represents a currently logged in user, null otherwise.
*/
public UserContext get(String authToken);
}

View File

@@ -0,0 +1,6 @@
/**
* Classes related to the authentication aspect of the Guacamole REST API.
*/
package org.glyptodon.guacamole.net.basic.rest.auth;

View File

@@ -0,0 +1,127 @@
package org.glyptodon.guacamole.net.basic.rest.connection;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.Connection;
import org.glyptodon.guacamole.net.auth.ConnectionRecord;
/**
* A simple connection to expose through the REST endpoints.
*
* @author James Muehlner
*/
public class APIConnection {
/**
* The name of this connection.
*/
private String name;
/**
* The identifier of this connection.
*/
private String identifier;
/**
* The history records associated with this connection.
*/
private List<? extends ConnectionRecord> history;
/**
* Map of all associated parameter values, indexed by parameter name.
*/
private Map<String, String> parameters = new HashMap<String, String>();
/**
* Create an empty APIConnection.
*/
public APIConnection() {}
/**
* Create an APIConnection from a Connection record.
* @param connection The connection to create this APIConnection from.
* @throws GuacamoleException If a problem is encountered while
* instantiating this new APIConnection.
*/
public APIConnection(Connection connection)
throws GuacamoleException {
this.name = connection.getName();
this.identifier = connection.getIdentifier();
this.history = connection.getHistory();
}
/**
* Returns the name of this connection.
* @return The name of this connection.
*/
public String getName() {
return name;
}
/**
* Set the name of this connection.
* @param name The name of this connection.
*/
public void setName(String name) {
this.name = name;
}
/**
* Returns the unique identifier for this connection.
* @return The unique identifier for this connection.
*/
public String getIdentifier() {
return identifier;
}
/**
* Sets the unique identifier for this connection.
*/
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
/**
* Returns the history records associated with this connection.
* @return The history records associated with this connection.
*/
public List<? extends ConnectionRecord> getHistory() {
return history;
}
/**
* Returns the parameter map for this connection.
* @return The parameter map for this connection.
*/
public Map<String, String> getParameters() {
return parameters;
}
/**
* Sets the parameter map for this connection.
* @param parameters The parameter map for this connection.
*/
public void setParameters(Map<String, String> parameters) {
this.parameters = parameters;
}
}

View File

@@ -0,0 +1,100 @@
package org.glyptodon.guacamole.net.basic.rest.connection;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.GuacamoleSocket;
import org.glyptodon.guacamole.net.auth.Connection;
import org.glyptodon.guacamole.net.auth.ConnectionRecord;
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
import org.glyptodon.guacamole.protocol.GuacamoleConfiguration;
/**
* A wrapper to make an APIConnection look like a Connection. Useful where a
* org.glyptodon.guacamole.net.auth.Connection is required.
*
* @author James Muehlner
*/
public class APIConnectionWrapper implements Connection {
private final APIConnection apiConnection;
public APIConnectionWrapper(APIConnection apiConnection) {
this.apiConnection = apiConnection;
}
@Override
public String getName() {
return apiConnection.getName();
}
@Override
public void setName(String name) {
apiConnection.setName(name);
}
@Override
public String getIdentifier() {
return apiConnection.getIdentifier();
}
@Override
public void setIdentifier(String identifier) {
apiConnection.setIdentifier(identifier);
}
@Override
public GuacamoleConfiguration getConfiguration() {
// Create the GuacamoleConfiguration from the parameter map
GuacamoleConfiguration configuration = new GuacamoleConfiguration();
Map<String, String> parameters = apiConnection.getParameters();
for(String key : parameters.keySet())
configuration.setParameter(key, parameters.get(key));
return configuration;
}
@Override
public void setConfiguration(GuacamoleConfiguration config) {
// Create a parameter map from the GuacamoleConfiguration
Map<String, String> newParameters = new HashMap<String, String>();
for(String key : config.getParameterNames())
newParameters.put(key, config.getParameter(key));
apiConnection.setParameters(newParameters);
}
@Override
public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException {
throw new UnsupportedOperationException("Operation not supported.");
}
@Override
public List<? extends ConnectionRecord> getHistory() throws GuacamoleException {
return apiConnection.getHistory();
}
}

View File

@@ -0,0 +1,320 @@
package org.glyptodon.guacamole.net.basic.rest.connection;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import com.google.inject.Inject;
import java.util.ArrayList;
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 javax.ws.rs.core.Response.Status;
import org.glyptodon.guacamole.GuacamoleClientException;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.GuacamoleSecurityException;
import org.glyptodon.guacamole.net.auth.Connection;
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
import org.glyptodon.guacamole.net.auth.Directory;
import org.glyptodon.guacamole.net.auth.UserContext;
import org.glyptodon.guacamole.net.basic.rest.HTTPException;
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A REST Service for handling connection CRUD operations.
*
* @author James Muehlner
*/
@Path("/api/connection")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class ConnectionRESTService {
/**
* Logger for this class.
*/
private static final Logger logger = LoggerFactory.getLogger(ConnectionRESTService.class);
/**
* A service for authenticating users from auth tokens.
*/
@Inject
private AuthenticationService authenticationService;
/**
* A service for managing the REST endpoint APIConnection objects.
*/
@Inject
private ConnectionService connectionService;
/**
* Gets a list of connections with the given ConnectionGroup parentID.
* If no parentID is provided, returns the connections from the root group.
*
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @param parentID The ID of the ConnectionGroup the connections
* belong to. If null, the root connection group will be used.
* @return The connection list.
*/
@GET
public List<APIConnection> getConnections(@QueryParam("token") String authToken, @QueryParam("parentID") String parentID) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
// If the parent connection group is passed in, try to find it.
ConnectionGroup parentConnectionGroup;
if(parentID == null)
parentConnectionGroup = userContext.getRootConnectionGroup();
else {
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
Directory<String, ConnectionGroup> connectionGroupDirectory = rootGroup.getConnectionGroupDirectory();
parentConnectionGroup = connectionGroupDirectory.get(parentID);
}
if(parentConnectionGroup == null)
throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided parentID.");
Directory<String, Connection> connectionDirectory =
parentConnectionGroup.getConnectionDirectory();
// Return the converted connection directory
return connectionService.convertConnectionList(connectionDirectory);
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught while listing connections.", e);
throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
/**
* Gets an individual connection.
*
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @param connectionID The ID of the Connection..
* @return The connection.
*/
@GET
@Path("/{connectionID}")
public APIConnection getConnection(@QueryParam("token") String authToken,
@PathParam("connectionID") String connectionID) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
// Get the connection directory
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
Directory<String, Connection> connectionDirectory =
rootGroup.getConnectionDirectory();
// Get the connection
Connection connection = connectionDirectory.get(connectionID);
if(connection == null)
throw new HTTPException(Status.NOT_FOUND, "No Connection found with the provided ID.");
return new APIConnection(connection);
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught while getting connection.", e);
throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
/**
* Deletes an individual connection.
*
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @param connectionID The ID of the Connection to delete.
*/
@DELETE
@Path("/{connectionID}")
public void deleteConnection(@QueryParam("token") String authToken, @PathParam("connectionID") String connectionID) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
// Get the connection directory
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
Directory<String, Connection> connectionDirectory =
rootGroup.getConnectionDirectory();
// Make sure the connection is there before trying to delete
if(connectionDirectory.get(connectionID) == null)
throw new HTTPException(Status.NOT_FOUND, "No Connection found with the provided ID.");
// Delete the connection
connectionDirectory.remove(connectionID);
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught while deleting connection.", e);
throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
/**
* Creates a new connection and returns the identifier of the new connection.
* If a parentID is provided, the connection will be created in the
* connection group with the parentID. Otherwise, the root connection group
* will be used.
*
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @param parentID The ID of the ConnectionGroup the connections
* belong to. If null, the root connection group will be used.
* @param connection The connection to create.
* @return The identifier of the new connection.
*/
@POST
public String createConnection(@QueryParam("token") String authToken,
@QueryParam("parentID") String parentID, APIConnection connection) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
if(connection == null)
throw new GuacamoleClientException("A connection is required for this request.");
// If the parent connection group is passed in, try to find it.
ConnectionGroup parentConnectionGroup;
if(parentID == null)
parentConnectionGroup = userContext.getRootConnectionGroup();
else {
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
Directory<String, ConnectionGroup> connectionGroupDirectory = rootGroup.getConnectionGroupDirectory();
parentConnectionGroup = connectionGroupDirectory.get(parentID);
}
if(parentConnectionGroup == null)
throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided parentID.");
Directory<String, Connection> connectionDirectory =
parentConnectionGroup.getConnectionDirectory();
// Create the connection
connectionDirectory.add(new APIConnectionWrapper(connection));
// Return the new connection identifier
return connection.getIdentifier();
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught while creating connection.", e);
throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
/**
* Updates a connection.
*
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @param connectionID The ID of the Connection to move.
* @param connection The connection to update.
*/
@POST
@Path("/{connectionID}")
public void updateConnection(@QueryParam("token") String authToken,
@PathParam("connectionID") String connectionID, APIConnection connection) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
if(connection == null)
throw new GuacamoleClientException("A connection is required for this request.");
// Get the connection directory
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
Directory<String, Connection> connectionDirectory =
rootGroup.getConnectionDirectory();
// Make sure the connection is there before trying to update
if(connectionDirectory.get(connectionID) == null)
throw new HTTPException(Status.NOT_FOUND, "No Connection found with the provided ID.");
// Update the connection
connectionDirectory.update(new APIConnectionWrapper(connection));
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught updating connection.", e);
throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
/**
* Moves an individual connection to a different connection group.
*
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @param connectionID The ID of the Connection to move.
* @param parentID The ID of the ConnectionGroup the connections
* belong to. If null, the root connection group will be used.
*/
@PUT
@Path("/{connectionID}")
public void moveConnection(@QueryParam("token") String authToken,
@PathParam("connectionID") String connectionID, @QueryParam("parentID") String parentID) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
// Get the connection directory
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
Directory<String, Connection> connectionDirectory =
rootGroup.getConnectionDirectory();
// Find the new parent connection group
Directory<String, ConnectionGroup> connectionGroupDirectory = rootGroup.getConnectionGroupDirectory();
ConnectionGroup parentConnectionGroup = connectionGroupDirectory.get(parentID);
if(parentConnectionGroup == null)
throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided parentID.");
// Move the connection
connectionDirectory.move(connectionID, parentConnectionGroup.getConnectionDirectory());
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught moving connection.", e);
throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
}

View File

@@ -0,0 +1,53 @@
package org.glyptodon.guacamole.net.basic.rest.connection;
import java.util.ArrayList;
import java.util.List;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.Connection;
import org.glyptodon.guacamole.net.auth.Directory;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* A service for performing useful manipulations on REST Connections.
*
* @author James Muehlner
*/
public class ConnectionService {
/**
* Converts a Connection Directory to a list of APIConnection objects for
* exposing with the REST endpoints.
*
* @param connectionDirectory The Connection Directory to convert for REST endpoint use.
* @return A List of APIConnection objects for use with the REST endpoint.
* @throws GuacamoleException If an error occurs while converting the
* connection directory.
*/
public List<APIConnection> convertConnectionList(Directory<String, Connection> connectionDirectory)
throws GuacamoleException {
List<APIConnection> restConnections = new ArrayList<APIConnection>();
for(String connectionID : connectionDirectory.getIdentifiers()) {
restConnections.add(new APIConnection(connectionDirectory.get(connectionID)));
}
return restConnections;
}
}

View File

@@ -0,0 +1,6 @@
/**
* Classes related to the connection manipulation aspect of the Guacamole REST API.
*/
package org.glyptodon.guacamole.net.basic.rest.connection;

View File

@@ -0,0 +1,110 @@
package org.glyptodon.guacamole.net.basic.rest.connectiongroup;
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
import org.glyptodon.guacamole.net.auth.ConnectionGroup.Type;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* A simple connection group to expose through the REST endpoints.
*
* @author James Muehlner
*/
public class APIConnectionGroup {
/**
* The name of this connection group.
*/
private String name;
/**
* The identifier of this connection group.
*/
private String identifier;
/**
* The type of this connection group.
*/
private Type type;
/**
* Create an empty APIConnectionGroup.
*/
public APIConnectionGroup() {}
/**
* Create a new APIConnectionGroup from the given ConnectionGroup record.
*
* @param connectionGroup The ConnectionGroup record to initialize this
* APIConnectionGroup from.
*/
public APIConnectionGroup(ConnectionGroup connectionGroup) {
this.identifier = connectionGroup.getIdentifier();
this.name = connectionGroup.getName();
this.type = connectionGroup.getType();
}
/**
* Returns the name of this connection group.
* @return The name of this connection group.
*/
public String getName() {
return name;
}
/**
* Set the name of this connection group.
* @param name The name of this connection group.
*/
public void setName(String name) {
this.name = name;
}
/**
* Returns the identifier of this connection group.
* @return The identifier of this connection group.
*/
public String getIdentifier() {
return identifier;
}
/**
* Set the identifier of this connection group.
* @param identifier The identifier of this connection group.
*/
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
/**
* Returns the type of this connection group.
* @return The type of this connection group.
*/
public Type getType() {
return type;
}
/**
* Set the type of this connection group.
* @param type The Type of this connection group.
*/
public void setType(Type type) {
this.type = type;
}
}

View File

@@ -0,0 +1,95 @@
package org.glyptodon.guacamole.net.basic.rest.connectiongroup;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.GuacamoleSocket;
import org.glyptodon.guacamole.net.auth.Connection;
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
import org.glyptodon.guacamole.net.auth.Directory;
import org.glyptodon.guacamole.protocol.GuacamoleClientInformation;
/**
* A wrapper to make an APIConnection look like a ConnectionGroup.
* Useful where a org.glyptodon.guacamole.net.auth.ConnectionGroup is required.
*
* @author James Muehlner
*/
public class APIConnectionGroupWrapper implements ConnectionGroup {
/**
* The wrapped APIConnectionGroup.
*/
private APIConnectionGroup apiConnectionGroup;
/**
* Create a new APIConnectionGroupWrapper to wrap the given
* APIConnectionGroup as a ConnectionGroup.
* @param apiConnectionGroup the APIConnectionGroup to wrap.
*/
public APIConnectionGroupWrapper(APIConnectionGroup apiConnectionGroup) {
this.apiConnectionGroup = apiConnectionGroup;
}
@Override
public String getName() {
return apiConnectionGroup.getName();
}
@Override
public void setName(String name) {
apiConnectionGroup.setName(name);
}
@Override
public String getIdentifier() {
return apiConnectionGroup.getIdentifier();
}
@Override
public void setIdentifier(String identifier) {
apiConnectionGroup.setIdentifier(identifier);
}
@Override
public void setType(Type type) {
apiConnectionGroup.setType(type);
}
@Override
public Type getType() {
return apiConnectionGroup.getType();
}
@Override
public Directory<String, Connection> getConnectionDirectory() throws GuacamoleException {
throw new UnsupportedOperationException("Operation not supported.");
}
@Override
public Directory<String, ConnectionGroup> getConnectionGroupDirectory() throws GuacamoleException {
throw new UnsupportedOperationException("Operation not supported.");
}
@Override
public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException {
throw new UnsupportedOperationException("Operation not supported.");
}
}

View File

@@ -0,0 +1,320 @@
package org.glyptodon.guacamole.net.basic.rest.connectiongroup;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import com.google.inject.Inject;
import java.util.ArrayList;
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 javax.ws.rs.core.Response.Status;
import org.glyptodon.guacamole.GuacamoleClientException;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.GuacamoleSecurityException;
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
import org.glyptodon.guacamole.net.auth.Directory;
import org.glyptodon.guacamole.net.auth.UserContext;
import org.glyptodon.guacamole.net.basic.rest.HTTPException;
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A REST Service for handling connection group CRUD operations.
*
* @author James Muehlner
*/
@Path("/api/connectionGroup")
@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;
/**
* A service for managing the REST endpoint APIConnection objects.
*/
@Inject
private ConnectionGroupService connectionGroupService;
/**
* Gets a list of connection groups with the given ConnectionGroup parentID.
* If no parentID is provided, returns the connection groups from the root group.
*
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @param parentID The ID of the ConnectionGroup the connection groups
* belong to. If null, the root connection group will be used.
* @return The connection list.
*/
@GET
public List<APIConnectionGroup> getConnectionGroups(@QueryParam("token") String authToken, @QueryParam("parentID") String parentID) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
// If the parent connection group is passed in, try to find it.
ConnectionGroup parentConnectionGroup;
if(parentID == null)
parentConnectionGroup = userContext.getRootConnectionGroup();
else {
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
Directory<String, ConnectionGroup> connectionGroupDirectory = rootGroup.getConnectionGroupDirectory();
parentConnectionGroup = connectionGroupDirectory.get(parentID);
}
if(parentConnectionGroup == null)
throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided parentID.");
Directory<String, ConnectionGroup> connectionGroupDirectory =
parentConnectionGroup.getConnectionGroupDirectory();
// return the converted connection group list
return connectionGroupService.convertConnectionGroupList(connectionGroupDirectory);
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught while listing connection groups.", e);
throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
/**
* Gets an individual connection group.
*
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @param connectionGroupID The ID of the ConnectionGroup.
* @return The connection group.
*/
@GET
@Path("/{connectionGroupID}")
public APIConnectionGroup getConnectionGroup(@QueryParam("token") String authToken,
@PathParam("connectionGroupID") String connectionGroupID) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
// Get the connection group directory
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
Directory<String, ConnectionGroup> connectionGroupDirectory =
rootGroup.getConnectionGroupDirectory();
// Get the connection group
ConnectionGroup connectionGroup = connectionGroupDirectory.get(connectionGroupID);
if(connectionGroup == null)
throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided ID.");
// Return the connectiion group
return new APIConnectionGroup(connectionGroup);
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught while getting connection group.", e);
throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
/**
* Deletes an individual connection group.
*
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @param connectionGroupID The ID of the ConnectionGroup to delete.
*/
@DELETE
@Path("/{connectionGroupID}")
public void deleteConnectionGroup(@QueryParam("token") String authToken, @PathParam("connectionGroupID") String connectionGroupID) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
// Get the connection group directory
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
Directory<String, ConnectionGroup> connectionGroupDirectory =
rootGroup.getConnectionGroupDirectory();
// Make sure the connection is there before trying to delete
if(connectionGroupDirectory.get(connectionGroupID) == null)
throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided ID.");
// Delete the connection group
connectionGroupDirectory.remove(connectionGroupID);
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught while deleting connection group.", e);
throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
/**
* Creates a new connection group and returns the identifier of the new connection group.
* If a parentID is provided, the connection group will be created in the
* connection group with the parentID. Otherwise, the root connection group
* will be used.
*
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @param parentID The ID of the ConnectionGroup the connection groups
* belong to. If null, the root connection group will be used.
* @param connection The connection group to create.
* @return The identifier of the new connection group.
*/
@POST
public String createConnectionGroup(@QueryParam("token") String authToken,
@QueryParam("parentID") String parentID, APIConnectionGroup connectionGroup) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
if(connectionGroup == null)
throw new GuacamoleClientException("A connection group is required for this request.");
// If the parent connection group is passed in, try to find it.
ConnectionGroup parentConnectionGroup;
if(parentID == null)
parentConnectionGroup = userContext.getRootConnectionGroup();
else {
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
Directory<String, ConnectionGroup> connectionGroupDirectory = rootGroup.getConnectionGroupDirectory();
parentConnectionGroup = connectionGroupDirectory.get(parentID);
}
if(parentConnectionGroup == null)
throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided parentID.");
Directory<String, ConnectionGroup> connectionGroupDirectory =
parentConnectionGroup.getConnectionGroupDirectory();
// Create the connection group
connectionGroupDirectory.add(new APIConnectionGroupWrapper(connectionGroup));
// Return the new connection group identifier
return connectionGroup.getIdentifier();
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught while creating connection group.", e);
throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
/**
* Updates a connection group.
*
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @param connectionID The ID of the ConnectionGroup to update.
* @param connection The connection group to update.
*/
@POST
@Path("/{connectionGroupID}")
public void updateConnectionGroup(@QueryParam("token") String authToken,
@PathParam("connectionGroupID") String connectionGroupID, APIConnectionGroup connectionGroup) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
if(connectionGroup == null)
throw new GuacamoleClientException("A connection is required for this request.");
// Get the connection directory
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
Directory<String, ConnectionGroup> connectionGroupDirectory =
rootGroup.getConnectionGroupDirectory();
// Make sure the connection group is there before trying to update
if(connectionGroupDirectory.get(connectionGroupID) == null)
throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided ID.");
// Update the connection group
connectionGroupDirectory.update(new APIConnectionGroupWrapper(connectionGroup));
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught updating connection group.", e);
throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
/**
* Moves an individual connection group to a different connection group.
*
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @param connectionID The ID of the ConnectionGroup to move.
* @param parentID The ID of the ConnectionGroup the connection groups
* belong to. If null, the root connection group will be used.
*/
@PUT
@Path("/{connectionGroupID}")
public void moveConnectionGroup(@QueryParam("token") String authToken,
@PathParam("connectionGroupID") String connectionGroupID, @QueryParam("parentID") String parentID) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
// Get the connection group directory
ConnectionGroup rootGroup = userContext.getRootConnectionGroup();
Directory<String, ConnectionGroup> connectionGroupDirectory =
rootGroup.getConnectionGroupDirectory();
// Find the new parent connection group
Directory<String, ConnectionGroup> newConnectionGroupDirectory = rootGroup.getConnectionGroupDirectory();
ConnectionGroup parentConnectionGroup = newConnectionGroupDirectory.get(parentID);
if(parentConnectionGroup == null)
throw new HTTPException(Status.NOT_FOUND, "No ConnectionGroup found with the provided parentID.");
// Move the connection group
connectionGroupDirectory.move(connectionGroupID, parentConnectionGroup.getConnectionGroupDirectory());
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught moving connection group.", e);
throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
}

View File

@@ -0,0 +1,53 @@
package org.glyptodon.guacamole.net.basic.rest.connectiongroup;
import java.util.ArrayList;
import java.util.List;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.ConnectionGroup;
import org.glyptodon.guacamole.net.auth.Directory;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* A service for performing useful manipulations on REST ConnectionGroups.
*
* @author James Muehlner
*/
public class ConnectionGroupService {
/**
* Converts a ConnectionGroup directory to a list of APIConnectionGroup
* objects for exposing with the REST endpoints.
*
* @param connectionGroupDirectory The ConnectionGroup Directory to convert for REST endpoint use.
* @return A List of APIConnectionGroup objects for use with the REST endpoint.
* @throws GuacamoleException If an error occurs while converting the
* connection group directory.
*/
public List<APIConnectionGroup> convertConnectionGroupList(
Directory<String, ConnectionGroup> connectionGroupDirectory) throws GuacamoleException {
List<APIConnectionGroup> restConnectionGroups = new ArrayList<APIConnectionGroup>();
for(String connectionGroupID : connectionGroupDirectory.getIdentifiers()) {
restConnectionGroups.add(new APIConnectionGroup(connectionGroupDirectory.get(connectionGroupID)));
}
return restConnectionGroups;
}
}

View File

@@ -0,0 +1,7 @@
/**
* Classes related to the connection group manipulation aspect
* of the Guacamole REST API.
*/
package org.glyptodon.guacamole.net.basic.rest.connectiongroup;

View File

@@ -0,0 +1,6 @@
/**
* Classes related to the basic Guacamole REST API.
*/
package org.glyptodon.guacamole.net.basic.rest;

View File

@@ -0,0 +1,200 @@
package org.glyptodon.guacamole.net.basic.rest.permission;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.glyptodon.guacamole.net.auth.permission.ConnectionGroupPermission;
import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission;
import org.glyptodon.guacamole.net.auth.permission.ObjectPermission;
import org.glyptodon.guacamole.net.auth.permission.Permission;
import org.glyptodon.guacamole.net.auth.permission.SystemPermission;
import org.glyptodon.guacamole.net.auth.permission.UserPermission;
/**
* A simple user permission to expose through the REST endpoints.
*
* @author James Muehlner
*/
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
public class APIPermission {
/**
* Create an empty APIPermission.
*/
public APIPermission() {}
/**
* The type of object that this permission refers to.
*/
private ObjectType objectType;
/**
* The type of object that a permission can refer to.
*/
public enum ObjectType {
CONNECTION,
CONNECTION_GROUP,
USER,
SYSTEM
}
/**
* The identifier of the object that this permission refers to.
*/
private String objectIdentifier;
/**
* The object permission type for this APIPermission, if relevant. This is
* only used if this.objectType is CONNECTION, CONNECTION_GROUP, or USER.
*/
private ObjectPermission.Type objectPermissionType;
/**
* The system permission type for this APIPermission, if relevant. This is
* only used if this.objectType is SYSTEM.
*/
private SystemPermission.Type systemPermissionType;
/**
* Create an APIConnection from a Connection record.
*
* @param permission The permission to create this APIPermission from.
*/
public APIPermission(Permission permission) {
if(permission instanceof ConnectionPermission) {
this.objectType = ObjectType.CONNECTION;
this.objectPermissionType = ((ConnectionPermission) permission).getType();
this.objectIdentifier = ((ConnectionPermission) permission).getObjectIdentifier();
} else if(permission instanceof ConnectionGroupPermission) {
this.objectType = ObjectType.CONNECTION_GROUP;
this.objectPermissionType = ((ConnectionGroupPermission) permission).getType();
this.objectIdentifier = ((ConnectionGroupPermission) permission).getObjectIdentifier();
} else if(permission instanceof UserPermission) {
this.objectType = ObjectType.USER;
this.objectPermissionType = ((UserPermission) permission).getType();
this.objectIdentifier = ((UserPermission) permission).getObjectIdentifier();
} else if(permission instanceof SystemPermission) {
this.objectType = ObjectType.SYSTEM;
this.systemPermissionType = ((SystemPermission) permission).getType();
}
}
/**
* Returns the type of object that this permission refers to.
*
* @return The type of object that this permission refers to.
*/
public ObjectType getObjectType() {
return objectType;
}
/**
* Set the type of object that this permission refers to.
* @param objectType The type of object that this permission refers to.
*/
public void setObjectType(ObjectType objectType) {
this.objectType = objectType;
}
/**
* Returns a string representation of the permission type.
* If this.objectType is CONNECTION, CONNECTION_GROUP, or USER, this will be
* the string representation of the objectPermissionType.
* If this.objectType is SYSTEM, this will be the string representation of
* the systemPermissionType.
*
* @return A string representation of the permission type.
*/
public String getPermissionType() {
switch(this.objectType) {
case CONNECTION:
case CONNECTION_GROUP:
case USER:
return this.objectPermissionType.toString();
case SYSTEM:
return this.systemPermissionType.toString();
default:
return null;
}
}
/**
* Set the permission type from a string representation of that type.
* Since it's not clear at this point whether this is an object permission or
* system permission, try to set both of them.
*
* @param permissionType The string representation of the permission type.
*/
public void setPermissionType(String permissionType) {
try {
this.objectPermissionType = ObjectPermission.Type.valueOf(permissionType);
} catch(IllegalArgumentException e) {}
try {
this.systemPermissionType = SystemPermission.Type.valueOf(permissionType);
} catch(IllegalArgumentException e) {}
}
/**
* Returns the identifier of the object that this permission refers to.
*
* @return The identifier of the object that this permission refers to.
*/
public String getObjectIdentifier() {
return objectIdentifier;
}
/**
* Set the identifier of the object that this permission refers to.
*
* @param objectIdentifier The identifier of the object that this permission refers to.
*/
public void setObjectIdentifier(String objectIdentifier) {
this.objectIdentifier = objectIdentifier;
}
/**
* Returns an org.glyptodon.guacamole.net.auth.permission.Permission
* representation of this APIPermission.
*
* @return An org.glyptodon.guacamole.net.auth.permission.Permission
* representation of this APIPermission.
*/
public Permission toPermission() {
switch(this.objectType) {
case CONNECTION:
return new ConnectionPermission
(this.objectPermissionType, this.objectIdentifier);
case CONNECTION_GROUP:
return new ConnectionGroupPermission
(this.objectPermissionType, this.objectIdentifier);
case USER:
return new UserPermission
(this.objectPermissionType, this.objectIdentifier);
case SYSTEM:
return new SystemPermission(this.systemPermissionType);
default:
return null;
}
}
}

View File

@@ -0,0 +1,167 @@
package org.glyptodon.guacamole.net.basic.rest.permission;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import com.google.inject.Inject;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
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 javax.ws.rs.core.Response.Status;
import org.glyptodon.guacamole.GuacamoleClientException;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.GuacamoleSecurityException;
import org.glyptodon.guacamole.net.auth.User;
import org.glyptodon.guacamole.net.auth.UserContext;
import org.glyptodon.guacamole.net.basic.rest.HTTPException;
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A REST Service for handling connection CRUD operations.
*
* @author James Muehlner
*/
@Path("/api/permission")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class PermissionRESTService {
/**
* Logger for this class.
*/
private static final Logger logger = LoggerFactory.getLogger(PermissionRESTService.class);
/**
* A service for authenticating users from auth tokens.
*/
@Inject
private AuthenticationService authenticationService;
/**
* A service for managing the REST endpoint APIPermission objects.
*/
@Inject
private PermissionService permissionService;
/**
* Gets a list of permissions for the user with the given userID.
*
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @param userID The ID of the user to retrieve permissions for.
* @return The permission list.
*/
@GET
@Path("/{userID}")
public List<APIPermission> getPermissions(@QueryParam("token") String authToken, @PathParam("userID") String userID) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
// Get the user
User user = userContext.getUserDirectory().get(userID);
if(user == null)
throw new HTTPException(Status.NOT_FOUND, "User not found with the provided userID.");
return permissionService.convertPermissionList(user.getPermissions());
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught while listing permissions.", e);
throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
/**
* Adds a permissions for a user with the given userID.
*
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @param userID The user ID to add the permission for.
* @param permission The permission to add for the user with the given userID.
*/
@POST
@Path("/{userID}")
public void addPermission(@QueryParam("token") String authToken,
@PathParam("userID") String userID, APIPermission permission) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
// Get the user
User user = userContext.getUserDirectory().get(userID);
if(user == null)
throw new HTTPException(Status.NOT_FOUND, "User not found with the provided userID.");
// Add the new permission
user.addPermission(permission.toPermission());
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught adding permission.", e);
throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
/**
* Removes a permissions for a user with the given userID.
*
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @param userID The user ID to remove the permission for.
* @param permission The permission to remove for the user with the given userID.
*/
@POST
@Path("/remove{userID}/")
public void removePermission(@QueryParam("token") String authToken,
@PathParam("userID") String userID, APIPermission permission) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
// Get the user
User user = userContext.getUserDirectory().get(userID);
if(user == null)
throw new HTTPException(Status.NOT_FOUND, "User not found with the provided userID.");
// Remove the permission
user.removePermission(permission.toPermission());
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught removing permission.", e);
throw new HTTPException(Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
}

View File

@@ -0,0 +1,67 @@
package org.glyptodon.guacamole.net.basic.rest.permission;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.glyptodon.guacamole.net.auth.permission.Permission;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* A service for performing useful manipulations on REST Permissions.
*
* @author James Muehlner
*/
public class PermissionService {
/**
* Converts a list of Permission to a list of APIPermission objects for
* exposing with the REST endpoints.
*
* @param permissions The Connections to convert for REST endpoint use.
* @return A List of APIPermission objects for use with the REST endpoint.
*/
public List<APIPermission> convertPermissionList(Iterable<? extends Permission> permissions) {
List<APIPermission> restPermissions = new ArrayList<APIPermission>();
for(Permission permission : permissions) {
restPermissions.add(new APIPermission(permission));
}
return restPermissions;
}
/**
* Converts a list of APIPermission to a set of Permission objects for internal
* Guacamole use.
*
* @param restPermissions The APIPermission objects from the REST endpoints.
* @return a List of Permission objects for internal Guacamole use.
*/
public Set<Permission> convertAPIPermissionList(Iterable<APIPermission> restPermissions) {
Set<Permission> permissions = new HashSet<Permission>();
for(APIPermission restPermission : restPermissions) {
permissions.add(restPermission.toPermission());
}
return permissions;
}
}

View File

@@ -0,0 +1,6 @@
/**
* Classes related to the permission manipulation aspect of the Guacamole REST API.
*/
package org.glyptodon.guacamole.net.basic.rest.permission;

View File

@@ -0,0 +1,82 @@
package org.glyptodon.guacamole.net.basic.rest.user;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import org.glyptodon.guacamole.net.auth.User;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* A simple User to expose through the REST endpoints.
*
* @author James Muehlner
*/
@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
public class APIUser {
/**
* The username of this user.
*/
private String username;
/**
* The password of this user.
*/
private String password;
/**
* Construct a new APIUser from the provided User.
* @param user The User to construct the APIUser from.
*/
public APIUser(User user) {
this.username = user.getUsername();
this.password = user.getPassword();
}
/**
* Returns the username for this user.
* @return The username for this user.
*/
public String getUsername() {
return username;
}
/**
* Set the username for this user.
* @param username The username for this user.
*/
public void setUsername(String username) {
this.username = username;
}
/**
* Returns the password for this user.
* @return The password for this user.
*/
public String getPassword() {
return password;
}
/**
* Set the password for this user.
* @param password The password for this user.
*/
public void setPassword(String password) {
this.password = password;
}
}

View File

@@ -0,0 +1,103 @@
package org.glyptodon.guacamole.net.basic.rest.user;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import java.util.Collections;
import java.util.Set;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.User;
import org.glyptodon.guacamole.net.auth.permission.Permission;
/**
* A wrapper to make an APIConnection look like a User. Useful where a
* org.glyptodon.guacamole.net.auth.User is required.
*
* @author James Muehlner
*/
public class APIUserWrapper implements User {
/**
* The wrapped APIUser.
*/
private APIUser apiUser;
/**
* The set of permissions for this user.
* NOTE: Not exposed by the REST endpoints.
*/
private Set<Permission> permissionSet = Collections.EMPTY_SET;
/**
* Wrap a given APIUser to expose as a User.
* @param apiUser The APIUser to wrap.
*/
public APIUserWrapper(APIUser apiUser) {
this.apiUser = apiUser;
}
/**
* Wrap a given APIUser to expose as a User, with the given permission set.
* @param apiUser The APIUser to wrap.
* @param permissionSet The set of permissions for the wrapped user.
*/
public APIUserWrapper(APIUser apiUser, Set<Permission> permissionSet) {
this.apiUser = apiUser;
this.permissionSet = permissionSet;
}
@Override
public String getUsername() {
return apiUser.getUsername();
}
@Override
public void setUsername(String username) {
apiUser.setUsername(username);
}
@Override
public String getPassword() {
return apiUser.getPassword();
}
@Override
public void setPassword(String password) {
apiUser.setPassword(password);
}
@Override
public Set<Permission> getPermissions() throws GuacamoleException {
return permissionSet;
}
@Override
public boolean hasPermission(Permission permission) throws GuacamoleException {
return permissionSet.contains(permission);
}
@Override
public void addPermission(Permission permission) throws GuacamoleException {
throw new UnsupportedOperationException("Operation not supported.");
}
@Override
public void removePermission(Permission permission) throws GuacamoleException {
throw new UnsupportedOperationException("Operation not supported.");
}
}

View File

@@ -0,0 +1,231 @@
package org.glyptodon.guacamole.net.basic.rest.user;
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.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.glyptodon.guacamole.GuacamoleClientException;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.GuacamoleSecurityException;
import org.glyptodon.guacamole.net.auth.Directory;
import org.glyptodon.guacamole.net.auth.User;
import org.glyptodon.guacamole.net.auth.UserContext;
import org.glyptodon.guacamole.net.basic.rest.HTTPException;
import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* A REST Service for handling user CRUD operations.
*
* @author James Muehlner
*/
@Path("/api/user")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class UserRESTService {
/**
* Logger for this class.
*/
private static final Logger logger = LoggerFactory.getLogger(UserRESTService.class);
/**
* A service for authenticating users from auth tokens.
*/
@Inject
private AuthenticationService authenticationService;
/**
* A service for managing the REST endpoint APIPermission objects.
*/
@Inject
private UserService userService;
/**
* Gets a list of users in the system.
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @return The user list.
*/
@GET
public List<APIUser> getUsers(@QueryParam("token") String authToken) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
// Get the directory
Directory<String, User> userDirectory = userContext.getUserDirectory();
// Convert and return the user directory listing
return userService.convertUserList(userDirectory);
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Response.Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Response.Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught while listing users.", e);
throw new HTTPException(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
/**
* Gets an individual user.
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @return user The user.
*/
@GET
@Path("/{userID}")
public APIUser getUser(@QueryParam("token") String authToken, @PathParam("userID") String userID) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
// Get the directory
Directory<String, User> userDirectory = userContext.getUserDirectory();
// Get the user
User user = userDirectory.get(userID);
if(user == null)
throw new HTTPException(Response.Status.NOT_FOUND, "User not found with the provided userID.");
// Return the user
return new APIUser(user);
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Response.Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Response.Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught while getting user.", e);
throw new HTTPException(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
/**
* Creates a new user and returns the username.
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @param user The new user to create.
*/
@POST
public String createUser(@QueryParam("token") String authToken, APIUser user) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
// Get the directory
Directory<String, User> userDirectory = userContext.getUserDirectory();
// Create the user
userDirectory.add(new APIUserWrapper(user));
return user.getUsername();
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Response.Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Response.Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught while creating user.", e);
throw new HTTPException(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
/**
* Updates an individual existing user.
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @param userID The unique identifier of the user to update.
* @param user The updated user.
*/
@POST
@Path("/{userID}")
public void updateUser(@QueryParam("token") String authToken, @PathParam("userID") String userID, APIUser user) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
// Get the directory
Directory<String, User> userDirectory = userContext.getUserDirectory();
if(!user.getUsername().equals(userID))
throw new HTTPException(Response.Status.BAD_REQUEST, "Username does not match provided userID.");
// Get the user
User existingUser = userDirectory.get(userID);
if(existingUser == null)
throw new HTTPException(Response.Status.NOT_FOUND, "User not found with the provided userID.");
/*
* Update the user with the permission set from the existing user
* since the user REST endpoints do not expose permissions
*/
userDirectory.update(new APIUserWrapper(user, existingUser.getPermissions()));
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Response.Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Response.Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught while updating user.", e);
throw new HTTPException(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
/**
* Deletes an individual existing user.
* @param authToken The authentication token that is used to authenticate
* the user performing the operation.
* @param userID The unique identifier of the user to delete.
*/
@DELETE
@Path("/{userID}")
public void deleteUser(@QueryParam("token") String authToken, @PathParam("userID") String userID) {
UserContext userContext = authenticationService.getUserContextFromAuthToken(authToken);
try {
// Get the directory
Directory<String, User> userDirectory = userContext.getUserDirectory();
// Get the user
User existingUser = userDirectory.get(userID);
if(existingUser == null)
throw new HTTPException(Response.Status.NOT_FOUND, "User not found with the provided userID.");
// Delete the user
userDirectory.remove(userID);
} catch(GuacamoleSecurityException e) {
throw new HTTPException(Response.Status.UNAUTHORIZED, e.getMessage() != null ? e.getMessage() : "Permission denied.");
} catch(GuacamoleClientException e) {
throw new HTTPException(Response.Status.BAD_REQUEST, e.getMessage() != null ? e.getMessage() : "Invalid Request.");
} catch(GuacamoleException e) {
logger.error("Unexpected GuacamoleException caught while deleting user.", e);
throw new HTTPException(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage() != null ? e.getMessage() : "Unexpected server error.");
}
}
}

View File

@@ -0,0 +1,54 @@
package org.glyptodon.guacamole.net.basic.rest.user;
import java.util.ArrayList;
import java.util.List;
import org.glyptodon.guacamole.GuacamoleException;
import org.glyptodon.guacamole.net.auth.Directory;
import org.glyptodon.guacamole.net.auth.User;
/*
* Guacamole - Clientless Remote Desktop
* Copyright (C) 2010 Michael Jumper
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* A service for performing useful manipulations on REST Users.
*
* @author James Muehlner
*/
public class UserService {
/**
* Converts a user directory to a list of APIUser objects for
* exposing with the REST endpoints.
*
* @param userDirectory The user directory to convert for REST endpoint use.
* @return A List of APIUser objects for use with the REST endpoint.
* @throws GuacamoleException If an error occurs while converting the
* user directory.
*/
public List<APIUser> convertUserList(Directory<String, User> userDirectory)
throws GuacamoleException {
List<APIUser> restUsers = new ArrayList<APIUser>();
for(String username : userDirectory.getIdentifiers()) {
restUsers.add(new APIUser(userDirectory.get(username)));
}
return restUsers;
}
}

View File

@@ -0,0 +1,6 @@
/**
* Classes related to the user manipulation aspect of the Guacamole REST API.
*/
package org.glyptodon.guacamole.net.basic.rest.user;

View File

@@ -241,7 +241,21 @@
<servlet-name>Tunnel</servlet-name> <servlet-name>Tunnel</servlet-name>
<url-pattern>/tunnel</url-pattern> <url-pattern>/tunnel</url-pattern>
</servlet-mapping> </servlet-mapping>
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/api/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.glyptodon.guacamole.net.basic.rest.RESTServletContextListener</listener-class>
</listener>
<mime-mapping> <mime-mapping>
<extension>mp3</extension> <extension>mp3</extension>
<mime-type>audio/mpeg</mime-type> <mime-type>audio/mpeg</mime-type>