You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by jm...@apache.org on 2016/03/29 06:20:13 UTC
[04/51] [abbrv] incubator-guacamole-client git commit: GUACAMOLE-1:
Remove useless .net.basic subpackage, now that everything is being renamed.
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java b/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java
new file mode 100644
index 0000000..5458aec
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2015 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.guacamole.rest;
+
+import com.google.inject.Scopes;
+import com.google.inject.matcher.Matchers;
+import com.google.inject.servlet.ServletModule;
+import com.sun.jersey.guice.spi.container.servlet.GuiceContainer;
+import org.aopalliance.intercept.MethodInterceptor;
+import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
+import org.apache.guacamole.rest.auth.TokenRESTService;
+import org.apache.guacamole.rest.connection.ConnectionRESTService;
+import org.apache.guacamole.rest.connectiongroup.ConnectionGroupRESTService;
+import org.apache.guacamole.rest.activeconnection.ActiveConnectionRESTService;
+import org.apache.guacamole.rest.auth.AuthTokenGenerator;
+import org.apache.guacamole.rest.auth.AuthenticationService;
+import org.apache.guacamole.rest.auth.SecureRandomAuthTokenGenerator;
+import org.apache.guacamole.rest.auth.TokenSessionMap;
+import org.apache.guacamole.rest.history.HistoryRESTService;
+import org.apache.guacamole.rest.language.LanguageRESTService;
+import org.apache.guacamole.rest.patch.PatchRESTService;
+import org.apache.guacamole.rest.schema.SchemaRESTService;
+import org.apache.guacamole.rest.user.UserRESTService;
+
+/**
+ * A Guice Module to set up the servlet mappings and authentication-specific
+ * dependency injection for the Guacamole REST API.
+ *
+ * @author James Muehlner
+ * @author Michael Jumper
+ */
+public class RESTServiceModule extends ServletModule {
+
+ /**
+ * Singleton instance of TokenSessionMap.
+ */
+ private final TokenSessionMap tokenSessionMap;
+
+ /**
+ * Creates a module which handles binding of REST services and related
+ * authentication objects, including the singleton TokenSessionMap.
+ *
+ * @param tokenSessionMap
+ * An instance of TokenSessionMap to inject as a singleton wherever
+ * needed.
+ */
+ public RESTServiceModule(TokenSessionMap tokenSessionMap) {
+ this.tokenSessionMap = tokenSessionMap;
+ }
+
+ @Override
+ protected void configureServlets() {
+
+ // Bind session map
+ bind(TokenSessionMap.class).toInstance(tokenSessionMap);
+
+ // Bind low-level services
+ bind(AuthenticationService.class);
+ bind(AuthTokenGenerator.class).to(SecureRandomAuthTokenGenerator.class);
+
+ // Automatically translate GuacamoleExceptions for REST methods
+ MethodInterceptor interceptor = new RESTExceptionWrapper();
+ requestInjection(interceptor);
+ bindInterceptor(Matchers.any(), new RESTMethodMatcher(), interceptor);
+
+ // Bind convenience services used by the REST API
+ bind(ObjectRetrievalService.class);
+
+ // Set up the API endpoints
+ bind(ActiveConnectionRESTService.class);
+ bind(ConnectionGroupRESTService.class);
+ bind(ConnectionRESTService.class);
+ bind(HistoryRESTService.class);
+ bind(LanguageRESTService.class);
+ bind(PatchRESTService.class);
+ bind(SchemaRESTService.class);
+ bind(TokenRESTService.class);
+ bind(UserRESTService.class);
+
+ // Set up the servlet and JSON mappings
+ bind(GuiceContainer.class);
+ bind(JacksonJsonProvider.class).in(Scopes.SINGLETON);
+ serve("/api/*").with(GuiceContainer.class);
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/APIActiveConnection.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/APIActiveConnection.java b/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/APIActiveConnection.java
new file mode 100644
index 0000000..b892333
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/APIActiveConnection.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2015 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.guacamole.rest.activeconnection;
+
+import java.util.Date;
+import org.apache.guacamole.net.auth.ActiveConnection;
+
+/**
+ * Information related to active connections which may be exposed through the
+ * REST endpoints.
+ *
+ * @author Michael Jumper
+ */
+public class APIActiveConnection {
+
+ /**
+ * The identifier of the active connection itself.
+ */
+ private final String identifier;
+
+ /**
+ * The identifier of the connection associated with this
+ * active connection.
+ */
+ private final String connectionIdentifier;
+
+ /**
+ * The date and time the connection began.
+ */
+ private final Date startDate;
+
+ /**
+ * The host from which the connection originated, if known.
+ */
+ private final String remoteHost;
+
+ /**
+ * The name of the user who used or is using the connection.
+ */
+ private final String username;
+
+ /**
+ * Creates a new APIActiveConnection, copying the information from the given
+ * active connection.
+ *
+ * @param connection
+ * The active connection to copy data from.
+ */
+ public APIActiveConnection(ActiveConnection connection) {
+ this.identifier = connection.getIdentifier();
+ this.connectionIdentifier = connection.getConnectionIdentifier();
+ this.startDate = connection.getStartDate();
+ this.remoteHost = connection.getRemoteHost();
+ this.username = connection.getUsername();
+ }
+
+ /**
+ * Returns the identifier of the connection associated with this tunnel.
+ *
+ * @return
+ * The identifier of the connection associated with this tunnel.
+ */
+ public String getConnectionIdentifier() {
+ return connectionIdentifier;
+ }
+
+ /**
+ * Returns the date and time the connection began.
+ *
+ * @return
+ * The date and time the connection began.
+ */
+ public Date getStartDate() {
+ return startDate;
+ }
+
+ /**
+ * Returns the remote host from which this connection originated.
+ *
+ * @return
+ * The remote host from which this connection originated.
+ */
+ public String getRemoteHost() {
+ return remoteHost;
+ }
+
+ /**
+ * Returns the name of the user who used or is using the connection at the
+ * times given by this tunnel.
+ *
+ * @return
+ * The name of the user who used or is using the associated connection.
+ */
+ public String getUsername() {
+ return username;
+ }
+
+ /**
+ * Returns the identifier of the active connection itself. This is
+ * distinct from the connection identifier, and uniquely identifies a
+ * specific use of a connection.
+ *
+ * @return
+ * The identifier of the active connection.
+ */
+ public String getIdentifier() {
+ return identifier;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionRESTService.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionRESTService.java b/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionRESTService.java
new file mode 100644
index 0000000..90e1608
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionRESTService.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2015 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.guacamole.rest.activeconnection;
+
+import com.google.inject.Inject;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import org.apache.guacamole.GuacamoleClientException;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.GuacamoleUnsupportedException;
+import org.apache.guacamole.net.auth.ActiveConnection;
+import org.apache.guacamole.net.auth.Directory;
+import org.apache.guacamole.net.auth.User;
+import org.apache.guacamole.net.auth.UserContext;
+import org.apache.guacamole.net.auth.permission.ObjectPermission;
+import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
+import org.apache.guacamole.net.auth.permission.SystemPermission;
+import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
+import org.apache.guacamole.GuacamoleSession;
+import org.apache.guacamole.rest.APIPatch;
+import org.apache.guacamole.rest.ObjectRetrievalService;
+import org.apache.guacamole.rest.PATCH;
+import org.apache.guacamole.rest.auth.AuthenticationService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A REST Service for retrieving and managing the tunnels of active connections.
+ *
+ * @author Michael Jumper
+ */
+@Path("/data/{dataSource}/activeConnections")
+@Produces(MediaType.APPLICATION_JSON)
+@Consumes(MediaType.APPLICATION_JSON)
+public class ActiveConnectionRESTService {
+
+ /**
+ * Logger for this class.
+ */
+ private static final Logger logger = LoggerFactory.getLogger(ActiveConnectionRESTService.class);
+
+ /**
+ * A service for authenticating users from auth tokens.
+ */
+ @Inject
+ private AuthenticationService authenticationService;
+
+ /**
+ * Service for convenient retrieval of objects.
+ */
+ @Inject
+ private ObjectRetrievalService retrievalService;
+
+ /**
+ * Gets a list of active connections in the system, filtering the returned
+ * list by the given permissions, if specified.
+ *
+ * @param authToken
+ * The authentication token that is used to authenticate the user
+ * performing the operation.
+ *
+ * @param authProviderIdentifier
+ * The unique identifier of the AuthenticationProvider associated with
+ * the UserContext containing the active connections to be retrieved.
+ *
+ * @param permissions
+ * The set of permissions to filter with. A user must have one or more
+ * of these permissions for a user to appear in the result.
+ * If null, no filtering will be performed.
+ *
+ * @return
+ * A list of all active connections. If a permission was specified,
+ * this list will contain only those active connections for which the
+ * current user has that permission.
+ *
+ * @throws GuacamoleException
+ * If an error is encountered while retrieving active connections.
+ */
+ @GET
+ public Map<String, APIActiveConnection> getActiveConnections(@QueryParam("token") String authToken,
+ @PathParam("dataSource") String authProviderIdentifier,
+ @QueryParam("permission") List<ObjectPermission.Type> permissions)
+ throws GuacamoleException {
+
+ GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
+ UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
+ User self = userContext.self();
+
+ // Do not filter on permissions if no permissions are specified
+ if (permissions != null && permissions.isEmpty())
+ permissions = null;
+
+ // An admin user has access to any connection
+ SystemPermissionSet systemPermissions = self.getSystemPermissions();
+ boolean isAdmin = systemPermissions.hasPermission(SystemPermission.Type.ADMINISTER);
+
+ // Get the directory
+ Directory<ActiveConnection> activeConnectionDirectory = userContext.getActiveConnectionDirectory();
+
+ // Filter connections, if requested
+ Collection<String> activeConnectionIdentifiers = activeConnectionDirectory.getIdentifiers();
+ if (!isAdmin && permissions != null) {
+ ObjectPermissionSet activeConnectionPermissions = self.getActiveConnectionPermissions();
+ activeConnectionIdentifiers = activeConnectionPermissions.getAccessibleObjects(permissions, activeConnectionIdentifiers);
+ }
+
+ // Retrieve all active connections , converting to API active connections
+ Map<String, APIActiveConnection> apiActiveConnections = new HashMap<String, APIActiveConnection>();
+ for (ActiveConnection activeConnection : activeConnectionDirectory.getAll(activeConnectionIdentifiers))
+ apiActiveConnections.put(activeConnection.getIdentifier(), new APIActiveConnection(activeConnection));
+
+ return apiActiveConnections;
+
+ }
+
+ /**
+ * Applies the given active connection patches. This operation currently
+ * only supports deletion of active connections through the "remove" patch
+ * operation. Deleting an active connection effectively kills the
+ * connection. The path of each patch operation is of the form "/ID"
+ * where ID is the identifier of the active connection being modified.
+ *
+ * @param authToken
+ * The authentication token that is used to authenticate the user
+ * performing the operation.
+ *
+ * @param authProviderIdentifier
+ * The unique identifier of the AuthenticationProvider associated with
+ * the UserContext containing the active connections to be deleted.
+ *
+ * @param patches
+ * The active connection patches to apply for this request.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while deleting the active connections.
+ */
+ @PATCH
+ public void patchTunnels(@QueryParam("token") String authToken,
+ @PathParam("dataSource") String authProviderIdentifier,
+ List<APIPatch<String>> patches) throws GuacamoleException {
+
+ GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
+ UserContext userContext = retrievalService.retrieveUserContext(session, authProviderIdentifier);
+
+ // Get the directory
+ Directory<ActiveConnection> activeConnectionDirectory = userContext.getActiveConnectionDirectory();
+
+ // Close each connection listed for removal
+ for (APIPatch<String> patch : patches) {
+
+ // Only remove is supported
+ if (patch.getOp() != APIPatch.Operation.remove)
+ throw new GuacamoleUnsupportedException("Only the \"remove\" operation is supported when patching active connections.");
+
+ // Retrieve and validate path
+ String path = patch.getPath();
+ if (!path.startsWith("/"))
+ throw new GuacamoleClientException("Patch paths must start with \"/\".");
+
+ // Close connection
+ activeConnectionDirectory.remove(path.substring(1));
+
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/auth/APIAuthenticationResponse.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/auth/APIAuthenticationResponse.java b/guacamole/src/main/java/org/apache/guacamole/rest/auth/APIAuthenticationResponse.java
new file mode 100644
index 0000000..f0a4306
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/auth/APIAuthenticationResponse.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2015 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.guacamole.rest.auth;
+
+/**
+ * A simple object to represent an auth token/username pair in the API.
+ *
+ * @author James Muehlner
+ */
+public class APIAuthenticationResponse {
+
+ /**
+ * The auth token.
+ */
+ private final String authToken;
+
+
+ /**
+ * The username of the user that authenticated.
+ */
+ private final String username;
+
+ /**
+ * The unique identifier of the data source from which this user account
+ * came. Although this user account may exist across several data sources
+ * (AuthenticationProviders), this will be the unique identifier of the
+ * AuthenticationProvider that authenticated this user for the current
+ * session.
+ */
+ private final String dataSource;
+
+ /**
+ * Returns the unique authentication token which identifies the current
+ * session.
+ *
+ * @return
+ * The user's authentication token.
+ */
+ public String getAuthToken() {
+ return authToken;
+ }
+
+ /**
+ * Returns the user identified by the authentication token associated with
+ * the current session.
+ *
+ * @return
+ * The user identified by this authentication token.
+ */
+ public String getUsername() {
+ return username;
+ }
+
+ /**
+ * Returns the unique identifier of the data source associated with the user
+ * account associated with this auth token.
+ *
+ * @return
+ * The unique identifier of the data source associated with the user
+ * account associated with this auth token.
+ */
+ public String getDataSource() {
+ return dataSource;
+ }
+
+ /**
+ * Create a new APIAuthToken Object with the given auth token.
+ *
+ * @param dataSource
+ * The unique identifier of the AuthenticationProvider which
+ * authenticated the user.
+ *
+ * @param authToken
+ * The auth token to create the new APIAuthToken with.
+ *
+ * @param username
+ * The username of the user owning the given token.
+ */
+ public APIAuthenticationResponse(String dataSource, String authToken, String username) {
+ this.dataSource = dataSource;
+ this.authToken = authToken;
+ this.username = username;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/auth/APIAuthenticationResult.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/auth/APIAuthenticationResult.java b/guacamole/src/main/java/org/apache/guacamole/rest/auth/APIAuthenticationResult.java
new file mode 100644
index 0000000..fa1c080
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/auth/APIAuthenticationResult.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2015 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.guacamole.rest.auth;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A simple object which describes the result of an authentication operation,
+ * including the resulting token.
+ *
+ * @author James Muehlner
+ * @author Michael Jumper
+ */
+public class APIAuthenticationResult {
+
+ /**
+ * The unique token generated for the user that authenticated.
+ */
+ private final String authToken;
+
+ /**
+ * The username of the user that authenticated.
+ */
+ private final String username;
+
+ /**
+ * The unique identifier of the data source from which this user account
+ * came. Although this user account may exist across several data sources
+ * (AuthenticationProviders), this will be the unique identifier of the
+ * AuthenticationProvider that authenticated this user for the current
+ * session.
+ */
+ private final String dataSource;
+
+ /**
+ * The identifiers of all data sources available to this user.
+ */
+ private final List<String> availableDataSources;
+
+ /**
+ * Returns the unique authentication token which identifies the current
+ * session.
+ *
+ * @return
+ * The user's authentication token.
+ */
+ public String getAuthToken() {
+ return authToken;
+ }
+
+ /**
+ * Returns the user identified by the authentication token associated with
+ * the current session.
+ *
+ * @return
+ * The user identified by this authentication token.
+ */
+ public String getUsername() {
+ return username;
+ }
+
+ /**
+ * Returns the unique identifier of the data source associated with the user
+ * account associated with the current session.
+ *
+ * @return
+ * The unique identifier of the data source associated with the user
+ * account associated with the current session.
+ */
+ public String getDataSource() {
+ return dataSource;
+ }
+
+ /**
+ * Returns the identifiers of all data sources available to the user
+ * associated with the current session.
+ *
+ * @return
+ * The identifiers of all data sources available to the user associated
+ * with the current session.
+ */
+ public List<String> getAvailableDataSources() {
+ return availableDataSources;
+ }
+
+ /**
+ * Create a new APIAuthenticationResult object containing the given data.
+ *
+ * @param authToken
+ * The unique token generated for the user that authenticated, to be
+ * used for the duration of their session.
+ *
+ * @param username
+ * The username of the user owning the given token.
+ *
+ * @param dataSource
+ * The unique identifier of the AuthenticationProvider which
+ * authenticated the user.
+ *
+ * @param availableDataSources
+ * The unique identifier of all AuthenticationProviders to which the
+ * user now has access.
+ */
+ public APIAuthenticationResult(String authToken, String username,
+ String dataSource, List<String> availableDataSources) {
+ this.authToken = authToken;
+ this.username = username;
+ this.dataSource = dataSource;
+ this.availableDataSources = Collections.unmodifiableList(availableDataSources);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/auth/AuthTokenGenerator.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/auth/AuthTokenGenerator.java b/guacamole/src/main/java/org/apache/guacamole/rest/auth/AuthTokenGenerator.java
new file mode 100644
index 0000000..cdab5aa
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/auth/AuthTokenGenerator.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.guacamole.rest.auth;
+
+/**
+ * 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();
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/auth/AuthenticationService.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/auth/AuthenticationService.java b/guacamole/src/main/java/org/apache/guacamole/rest/auth/AuthenticationService.java
new file mode 100644
index 0000000..7fa51e5
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/auth/AuthenticationService.java
@@ -0,0 +1,475 @@
+/*
+ * Copyright (C) 2015 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.guacamole.rest.auth;
+
+import com.google.inject.Inject;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.GuacamoleSecurityException;
+import org.apache.guacamole.GuacamoleUnauthorizedException;
+import org.apache.guacamole.environment.Environment;
+import org.apache.guacamole.net.auth.AuthenticatedUser;
+import org.apache.guacamole.net.auth.AuthenticationProvider;
+import org.apache.guacamole.net.auth.Credentials;
+import org.apache.guacamole.net.auth.UserContext;
+import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
+import org.apache.guacamole.net.auth.credentials.GuacamoleCredentialsException;
+import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
+import org.apache.guacamole.GuacamoleSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A service for performing authentication checks in REST endpoints.
+ *
+ * @author James Muehlner
+ * @author Michael Jumper
+ */
+public class AuthenticationService {
+
+ /**
+ * Logger for this class.
+ */
+ private static final Logger logger = LoggerFactory.getLogger(AuthenticationService.class);
+
+ /**
+ * The Guacamole server environment.
+ */
+ @Inject
+ private Environment environment;
+
+ /**
+ * All configured authentication providers which can be used to
+ * authenticate users or retrieve data associated with authenticated users.
+ */
+ @Inject
+ private List<AuthenticationProvider> authProviders;
+
+ /**
+ * The map of auth tokens to sessions for the REST endpoints.
+ */
+ @Inject
+ private TokenSessionMap tokenSessionMap;
+
+ /**
+ * A generator for creating new auth tokens.
+ */
+ @Inject
+ private AuthTokenGenerator authTokenGenerator;
+
+ /**
+ * Regular expression which matches any IPv4 address.
+ */
+ private static final String IPV4_ADDRESS_REGEX = "([0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})";
+
+ /**
+ * Regular expression which matches any IPv6 address.
+ */
+ private static final String IPV6_ADDRESS_REGEX = "([0-9a-fA-F]*(:[0-9a-fA-F]*){0,7})";
+
+ /**
+ * Regular expression which matches any IP address, regardless of version.
+ */
+ private static final String IP_ADDRESS_REGEX = "(" + IPV4_ADDRESS_REGEX + "|" + IPV6_ADDRESS_REGEX + ")";
+
+ /**
+ * Pattern which matches valid values of the de-facto standard
+ * "X-Forwarded-For" header.
+ */
+ private static final Pattern X_FORWARDED_FOR = Pattern.compile("^" + IP_ADDRESS_REGEX + "(, " + IP_ADDRESS_REGEX + ")*$");
+
+ /**
+ * Returns a formatted string containing an IP address, or list of IP
+ * addresses, which represent the HTTP client and any involved proxies. As
+ * the headers used to determine proxies can easily be forged, this data is
+ * superficially validated to ensure that it at least looks like a list of
+ * IPs.
+ *
+ * @param request
+ * The HTTP request to format.
+ *
+ * @return
+ * A formatted string containing one or more IP addresses.
+ */
+ private String getLoggableAddress(HttpServletRequest request) {
+
+ // Log X-Forwarded-For, if present and valid
+ String header = request.getHeader("X-Forwarded-For");
+ if (header != null && X_FORWARDED_FOR.matcher(header).matches())
+ return "[" + header + ", " + request.getRemoteAddr() + "]";
+
+ // If header absent or invalid, just use source IP
+ return request.getRemoteAddr();
+
+ }
+
+ /**
+ * Attempts authentication against all AuthenticationProviders, in order,
+ * using the provided credentials. The first authentication failure takes
+ * priority, but remaining AuthenticationProviders are attempted. If any
+ * AuthenticationProvider succeeds, the resulting AuthenticatedUser is
+ * returned, and no further AuthenticationProviders are tried.
+ *
+ * @param credentials
+ * The credentials to use for authentication.
+ *
+ * @return
+ * The AuthenticatedUser given by the highest-priority
+ * AuthenticationProvider for which the given credentials are valid.
+ *
+ * @throws GuacamoleException
+ * If the given credentials are not valid for any
+ * AuthenticationProvider, or if an error occurs while authenticating
+ * the user.
+ */
+ private AuthenticatedUser authenticateUser(Credentials credentials)
+ throws GuacamoleException {
+
+ GuacamoleCredentialsException authFailure = null;
+
+ // Attempt authentication against each AuthenticationProvider
+ for (AuthenticationProvider authProvider : authProviders) {
+
+ // Attempt authentication
+ try {
+ AuthenticatedUser authenticatedUser = authProvider.authenticateUser(credentials);
+ if (authenticatedUser != null)
+ return authenticatedUser;
+ }
+
+ // First failure takes priority for now
+ catch (GuacamoleCredentialsException e) {
+ if (authFailure == null)
+ authFailure = e;
+ }
+
+ }
+
+ // If a specific failure occured, rethrow that
+ if (authFailure != null)
+ throw authFailure;
+
+ // Otherwise, request standard username/password
+ throw new GuacamoleInvalidCredentialsException(
+ "Permission Denied.",
+ CredentialsInfo.USERNAME_PASSWORD
+ );
+
+ }
+
+ /**
+ * Re-authenticates the given AuthenticatedUser against the
+ * AuthenticationProvider that originally created it, using the given
+ * Credentials.
+ *
+ * @param authenticatedUser
+ * The AuthenticatedUser to re-authenticate.
+ *
+ * @param credentials
+ * The Credentials to use to re-authenticate the user.
+ *
+ * @return
+ * A AuthenticatedUser which may have been updated due to re-
+ * authentication.
+ *
+ * @throws GuacamoleException
+ * If an error prevents the user from being re-authenticated.
+ */
+ private AuthenticatedUser updateAuthenticatedUser(AuthenticatedUser authenticatedUser,
+ Credentials credentials) throws GuacamoleException {
+
+ // Get original AuthenticationProvider
+ AuthenticationProvider authProvider = authenticatedUser.getAuthenticationProvider();
+
+ // Re-authenticate the AuthenticatedUser against the original AuthenticationProvider only
+ authenticatedUser = authProvider.updateAuthenticatedUser(authenticatedUser, credentials);
+ if (authenticatedUser == null)
+ throw new GuacamoleSecurityException("User re-authentication failed.");
+
+ return authenticatedUser;
+
+ }
+
+ /**
+ * Returns the AuthenticatedUser associated with the given session and
+ * credentials, performing a fresh authentication and creating a new
+ * AuthenticatedUser if necessary.
+ *
+ * @param existingSession
+ * The current GuacamoleSession, or null if no session exists yet.
+ *
+ * @param credentials
+ * The Credentials to use to authenticate the user.
+ *
+ * @return
+ * The AuthenticatedUser associated with the given session and
+ * credentials.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while authenticating or re-authenticating the
+ * user.
+ */
+ private AuthenticatedUser getAuthenticatedUser(GuacamoleSession existingSession,
+ Credentials credentials) throws GuacamoleException {
+
+ try {
+
+ // Re-authenticate user if session exists
+ if (existingSession != null)
+ return updateAuthenticatedUser(existingSession.getAuthenticatedUser(), credentials);
+
+ // Otherwise, attempt authentication as a new user
+ AuthenticatedUser authenticatedUser = AuthenticationService.this.authenticateUser(credentials);
+ if (logger.isInfoEnabled())
+ logger.info("User \"{}\" successfully authenticated from {}.",
+ authenticatedUser.getIdentifier(),
+ getLoggableAddress(credentials.getRequest()));
+
+ return authenticatedUser;
+
+ }
+
+ // Log and rethrow any authentication errors
+ catch (GuacamoleException e) {
+
+ // Get request and username for sake of logging
+ HttpServletRequest request = credentials.getRequest();
+ String username = credentials.getUsername();
+
+ // Log authentication failures with associated usernames
+ if (username != null) {
+ if (logger.isWarnEnabled())
+ logger.warn("Authentication attempt from {} for user \"{}\" failed.",
+ getLoggableAddress(request), username);
+ }
+
+ // Log anonymous authentication failures
+ else if (logger.isDebugEnabled())
+ logger.debug("Anonymous authentication attempt from {} failed.",
+ getLoggableAddress(request));
+
+ // Rethrow exception
+ throw e;
+
+ }
+
+ }
+
+ /**
+ * Returns all UserContexts associated with the given AuthenticatedUser,
+ * updating existing UserContexts, if any. If no UserContexts are yet
+ * associated with the given AuthenticatedUser, new UserContexts are
+ * generated by polling each available AuthenticationProvider.
+ *
+ * @param existingSession
+ * The current GuacamoleSession, or null if no session exists yet.
+ *
+ * @param authenticatedUser
+ * The AuthenticatedUser that has successfully authenticated or re-
+ * authenticated.
+ *
+ * @return
+ * A List of all UserContexts associated with the given
+ * AuthenticatedUser.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while creating or updating any UserContext.
+ */
+ private List<UserContext> getUserContexts(GuacamoleSession existingSession,
+ AuthenticatedUser authenticatedUser) throws GuacamoleException {
+
+ List<UserContext> userContexts = new ArrayList<UserContext>(authProviders.size());
+
+ // If UserContexts already exist, update them and add to the list
+ if (existingSession != null) {
+
+ // Update all old user contexts
+ List<UserContext> oldUserContexts = existingSession.getUserContexts();
+ for (UserContext oldUserContext : oldUserContexts) {
+
+ // Update existing UserContext
+ AuthenticationProvider authProvider = oldUserContext.getAuthenticationProvider();
+ UserContext userContext = authProvider.updateUserContext(oldUserContext, authenticatedUser);
+
+ // Add to available data, if successful
+ if (userContext != null)
+ userContexts.add(userContext);
+
+ // If unsuccessful, log that this happened, as it may be a bug
+ else
+ logger.debug("AuthenticationProvider \"{}\" retroactively destroyed its UserContext.",
+ authProvider.getClass().getName());
+
+ }
+
+ }
+
+ // Otherwise, create new UserContexts from available AuthenticationProviders
+ else {
+
+ // Get UserContexts from each available AuthenticationProvider
+ for (AuthenticationProvider authProvider : authProviders) {
+
+ // Generate new UserContext
+ UserContext userContext = authProvider.getUserContext(authenticatedUser);
+
+ // Add to available data, if successful
+ if (userContext != null)
+ userContexts.add(userContext);
+
+ }
+
+ }
+
+ return userContexts;
+
+ }
+
+ /**
+ * Authenticates a user using the given credentials and optional
+ * authentication token, returning the authentication token associated with
+ * the user's Guacamole session, which may be newly generated. If an
+ * existing token is provided, the authentication procedure will attempt to
+ * update or reuse the provided token, but it is possible that a new token
+ * will be returned. Note that this function CANNOT return null.
+ *
+ * @param credentials
+ * The credentials to use when authenticating the user.
+ *
+ * @param token
+ * The authentication token to use if attempting to re-authenticate an
+ * existing session, or null to request a new token.
+ *
+ * @return
+ * The authentication token associated with the newly created or
+ * existing session.
+ *
+ * @throws GuacamoleException
+ * If the authentication or re-authentication attempt fails.
+ */
+ public String authenticate(Credentials credentials, String token)
+ throws GuacamoleException {
+
+ // Pull existing session if token provided
+ GuacamoleSession existingSession;
+ if (token != null)
+ existingSession = tokenSessionMap.get(token);
+ else
+ existingSession = null;
+
+ // Get up-to-date AuthenticatedUser and associated UserContexts
+ AuthenticatedUser authenticatedUser = getAuthenticatedUser(existingSession, credentials);
+ List<UserContext> userContexts = getUserContexts(existingSession, authenticatedUser);
+
+ // Update existing session, if it exists
+ String authToken;
+ if (existingSession != null) {
+ authToken = token;
+ existingSession.setAuthenticatedUser(authenticatedUser);
+ existingSession.setUserContexts(userContexts);
+ }
+
+ // If no existing session, generate a new token/session pair
+ else {
+ authToken = authTokenGenerator.getToken();
+ tokenSessionMap.put(authToken, new GuacamoleSession(environment, authenticatedUser, userContexts));
+ logger.debug("Login was successful for user \"{}\".", authenticatedUser.getIdentifier());
+ }
+
+ return authToken;
+
+ }
+
+ /**
+ * Finds the Guacamole session 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 session that corresponds to the provided auth token.
+ * @throws GuacamoleException If the auth token does not correspond to any
+ * logged in user.
+ */
+ public GuacamoleSession getGuacamoleSession(String authToken)
+ throws GuacamoleException {
+
+ // Try to get the session from the map of logged in users.
+ GuacamoleSession session = tokenSessionMap.get(authToken);
+
+ // Authentication failed.
+ if (session == null)
+ throw new GuacamoleUnauthorizedException("Permission Denied.");
+
+ return session;
+
+ }
+
+ /**
+ * Invalidates a specific authentication token and its corresponding
+ * Guacamole session, effectively logging out the associated user. If the
+ * authentication token is not valid, this function has no effect.
+ *
+ * @param authToken
+ * The token being invalidated.
+ *
+ * @return
+ * true if the given authentication token was valid and the
+ * corresponding Guacamole session was destroyed, false if the given
+ * authentication token was not valid and no action was taken.
+ */
+ public boolean destroyGuacamoleSession(String authToken) {
+
+ // Remove corresponding GuacamoleSession if the token is valid
+ GuacamoleSession session = tokenSessionMap.remove(authToken);
+ if (session == null)
+ return false;
+
+ // Invalidate the removed session
+ session.invalidate();
+ return true;
+
+ }
+
+ /**
+ * Returns all UserContexts associated with 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
+ * A List of all UserContexts associated with the provided auth token.
+ *
+ * @throws GuacamoleException
+ * If the auth token does not correspond to any logged in user.
+ */
+ public List<UserContext> getUserContexts(String authToken)
+ throws GuacamoleException {
+ return getGuacamoleSession(authToken).getUserContexts();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/auth/BasicTokenSessionMap.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/auth/BasicTokenSessionMap.java b/guacamole/src/main/java/org/apache/guacamole/rest/auth/BasicTokenSessionMap.java
new file mode 100644
index 0000000..9de33fb
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/auth/BasicTokenSessionMap.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2014 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.guacamole.rest.auth;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.environment.Environment;
+import org.apache.guacamole.GuacamoleSession;
+import org.apache.guacamole.properties.BasicGuacamoleProperties;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A basic, HashMap-based implementation of the TokenSessionMap with support
+ * for session timeouts.
+ *
+ * @author James Muehlner
+ */
+public class BasicTokenSessionMap implements TokenSessionMap {
+
+ /**
+ * Logger for this class.
+ */
+ private static final Logger logger = LoggerFactory.getLogger(BasicTokenSessionMap.class);
+
+ /**
+ * Executor service which runs the period session eviction task.
+ */
+ private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
+
+ /**
+ * Keeps track of the authToken to GuacamoleSession mapping.
+ */
+ private final ConcurrentMap<String, GuacamoleSession> sessionMap =
+ new ConcurrentHashMap<String, GuacamoleSession>();
+
+ /**
+ * Create a new BasicTokenGuacamoleSessionMap configured using the given
+ * environment.
+ *
+ * @param environment
+ * The environment to use when configuring the token session map.
+ */
+ public BasicTokenSessionMap(Environment environment) {
+
+ int sessionTimeoutValue;
+
+ // Read session timeout from guacamole.properties
+ try {
+ sessionTimeoutValue = environment.getProperty(BasicGuacamoleProperties.API_SESSION_TIMEOUT, 60);
+ }
+ catch (GuacamoleException e) {
+ logger.error("Unable to read guacamole.properties: {}", e.getMessage());
+ logger.debug("Error while reading session timeout value.", e);
+ sessionTimeoutValue = 60;
+ }
+
+ // Check for expired sessions every minute
+ logger.info("Sessions will expire after {} minutes of inactivity.", sessionTimeoutValue);
+ executor.scheduleAtFixedRate(new SessionEvictionTask(sessionTimeoutValue * 60000l), 1, 1, TimeUnit.MINUTES);
+
+ }
+
+ /**
+ * Task which iterates through all active sessions, evicting those sessions
+ * which are beyond the session timeout.
+ */
+ private class SessionEvictionTask implements Runnable {
+
+ /**
+ * The maximum allowed age of any session, in milliseconds.
+ */
+ private final long sessionTimeout;
+
+ /**
+ * Creates a new task which automatically evicts sessions which are
+ * older than the specified timeout.
+ *
+ * @param sessionTimeout The maximum age of any session, in
+ * milliseconds.
+ */
+ public SessionEvictionTask(long sessionTimeout) {
+ this.sessionTimeout = sessionTimeout;
+ }
+
+ @Override
+ public void run() {
+
+ // Get start time of session check time
+ long sessionCheckStart = System.currentTimeMillis();
+
+ logger.debug("Checking for expired sessions...");
+
+ // For each session, remove sesions which have expired
+ Iterator<Map.Entry<String, GuacamoleSession>> entries = sessionMap.entrySet().iterator();
+ while (entries.hasNext()) {
+
+ Map.Entry<String, GuacamoleSession> entry = entries.next();
+ GuacamoleSession session = entry.getValue();
+
+ // Do not expire sessions which are active
+ if (session.hasTunnels())
+ continue;
+
+ // Get elapsed time since last access
+ long age = sessionCheckStart - session.getLastAccessedTime();
+
+ // If session is too old, evict it and check the next one
+ if (age >= sessionTimeout) {
+ logger.debug("Session \"{}\" has timed out.", entry.getKey());
+ entries.remove();
+ session.invalidate();
+ }
+
+ }
+
+ // Log completion and duration
+ logger.debug("Session check completed in {} ms.",
+ System.currentTimeMillis() - sessionCheckStart);
+
+ }
+
+ }
+
+ @Override
+ public GuacamoleSession get(String authToken) {
+
+ // There are no null auth tokens
+ if (authToken == null)
+ return null;
+
+ // Update the last access time and return the GuacamoleSession
+ GuacamoleSession session = sessionMap.get(authToken);
+ if (session != null)
+ session.access();
+
+ return session;
+
+ }
+
+ @Override
+ public void put(String authToken, GuacamoleSession session) {
+ sessionMap.put(authToken, session);
+ }
+
+ @Override
+ public GuacamoleSession remove(String authToken) {
+
+ // There are no null auth tokens
+ if (authToken == null)
+ return null;
+
+ // Attempt to retrieve only if non-null
+ return sessionMap.remove(authToken);
+
+ }
+
+ @Override
+ public void shutdown() {
+ executor.shutdownNow();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/auth/SecureRandomAuthTokenGenerator.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/auth/SecureRandomAuthTokenGenerator.java b/guacamole/src/main/java/org/apache/guacamole/rest/auth/SecureRandomAuthTokenGenerator.java
new file mode 100644
index 0000000..ed93bd4
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/auth/SecureRandomAuthTokenGenerator.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.guacamole.rest.auth;
+
+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 final SecureRandom secureRandom = new SecureRandom();
+
+ @Override
+ public String getToken() {
+ byte[] bytes = new byte[32];
+ secureRandom.nextBytes(bytes);
+
+ return Hex.encodeHexString(bytes);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/auth/TokenRESTService.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/auth/TokenRESTService.java b/guacamole/src/main/java/org/apache/guacamole/rest/auth/TokenRESTService.java
new file mode 100644
index 0000000..5a062fb
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/auth/TokenRESTService.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2015 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.guacamole.rest.auth;
+
+import com.google.inject.Inject;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.xml.bind.DatatypeConverter;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.GuacamoleResourceNotFoundException;
+import org.apache.guacamole.net.auth.AuthenticatedUser;
+import org.apache.guacamole.net.auth.Credentials;
+import org.apache.guacamole.net.auth.UserContext;
+import org.apache.guacamole.GuacamoleSession;
+import org.apache.guacamole.rest.APIRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A service for managing auth tokens via the Guacamole REST API.
+ *
+ * @author James Muehlner
+ * @author Michael Jumper
+ */
+@Path("/tokens")
+@Produces(MediaType.APPLICATION_JSON)
+public class TokenRESTService {
+
+ /**
+ * Logger for this class.
+ */
+ private static final Logger logger = LoggerFactory.getLogger(TokenRESTService.class);
+
+ /**
+ * Service for authenticating users and managing their Guacamole sessions.
+ */
+ @Inject
+ private AuthenticationService authenticationService;
+
+ /**
+ * Returns the credentials associated with the given request, using the
+ * provided username and password.
+ *
+ * @param request
+ * The request to use to derive the credentials.
+ *
+ * @param username
+ * The username to associate with the credentials, or null if the
+ * username should be derived from the request.
+ *
+ * @param password
+ * The password to associate with the credentials, or null if the
+ * password should be derived from the request.
+ *
+ * @return
+ * A new Credentials object whose contents have been derived from the
+ * given request, along with the provided username and password.
+ */
+ private Credentials getCredentials(HttpServletRequest request,
+ String username, String password) {
+
+ // If no username/password given, try Authorization header
+ if (username == null && password == null) {
+
+ String authorization = request.getHeader("Authorization");
+ if (authorization != null && authorization.startsWith("Basic ")) {
+
+ try {
+
+ // Decode base64 authorization
+ String basicBase64 = authorization.substring(6);
+ String basicCredentials = new String(DatatypeConverter.parseBase64Binary(basicBase64), "UTF-8");
+
+ // Pull username/password from auth data
+ int colon = basicCredentials.indexOf(':');
+ if (colon != -1) {
+ username = basicCredentials.substring(0, colon);
+ password = basicCredentials.substring(colon + 1);
+ }
+ else
+ logger.debug("Invalid HTTP Basic \"Authorization\" header received.");
+
+ }
+
+ // UTF-8 support is required by the Java specification
+ catch (UnsupportedEncodingException e) {
+ throw new UnsupportedOperationException("Unexpected lack of UTF-8 support.", e);
+ }
+
+ }
+
+ } // end Authorization header fallback
+
+ // Build credentials
+ Credentials credentials = new Credentials();
+ credentials.setUsername(username);
+ credentials.setPassword(password);
+ credentials.setRequest(request);
+ credentials.setSession(request.getSession(true));
+
+ return credentials;
+
+ }
+
+ /**
+ * Authenticates a user, generates an auth token, associates that auth token
+ * with the user's UserContext for use by further requests. If an existing
+ * token is provided, the authentication procedure will attempt to update
+ * or reuse the provided token.
+ *
+ * @param username
+ * The username of the user who is to be authenticated.
+ *
+ * @param password
+ * The password of the user who is to be authenticated.
+ *
+ * @param token
+ * An optional existing auth token for the user who is to be
+ * authenticated.
+ *
+ * @param consumedRequest
+ * The HttpServletRequest associated with the login attempt. The
+ * parameters of this request may not be accessible, as the request may
+ * have been fully consumed by JAX-RS.
+ *
+ * @param parameters
+ * A MultivaluedMap containing all parameters from the given HTTP
+ * request. All request parameters must be made available through this
+ * map, even if those parameters are no longer accessible within the
+ * now-fully-consumed HTTP request.
+ *
+ * @return
+ * An authentication response object containing the possible-new auth
+ * token, as well as other related data.
+ *
+ * @throws GuacamoleException
+ * If an error prevents successful authentication.
+ */
+ @POST
+ public APIAuthenticationResult createToken(@FormParam("username") String username,
+ @FormParam("password") String password,
+ @FormParam("token") String token,
+ @Context HttpServletRequest consumedRequest,
+ MultivaluedMap<String, String> parameters)
+ throws GuacamoleException {
+
+ // Reconstitute the HTTP request with the map of parameters
+ HttpServletRequest request = new APIRequest(consumedRequest, parameters);
+
+ // Build credentials from request
+ Credentials credentials = getCredentials(request, username, password);
+
+ // Create/update session producing possibly-new token
+ token = authenticationService.authenticate(credentials, token);
+
+ // Pull corresponding session
+ GuacamoleSession session = authenticationService.getGuacamoleSession(token);
+ if (session == null)
+ throw new GuacamoleResourceNotFoundException("No such token.");
+
+ // Build list of all available auth providers
+ List<UserContext> userContexts = session.getUserContexts();
+ List<String> authProviderIdentifiers = new ArrayList<String>(userContexts.size());
+ for (UserContext userContext : userContexts)
+ authProviderIdentifiers.add(userContext.getAuthenticationProvider().getIdentifier());
+
+ // Return possibly-new auth token
+ AuthenticatedUser authenticatedUser = session.getAuthenticatedUser();
+ return new APIAuthenticationResult(
+ token,
+ authenticatedUser.getIdentifier(),
+ authenticatedUser.getAuthenticationProvider().getIdentifier(),
+ authProviderIdentifiers
+ );
+
+ }
+
+ /**
+ * Invalidates a specific auth token, effectively logging out the associated
+ * user.
+ *
+ * @param authToken
+ * The token being invalidated.
+ *
+ * @throws GuacamoleException
+ * If the specified token does not exist.
+ */
+ @DELETE
+ @Path("/{token}")
+ public void invalidateToken(@PathParam("token") String authToken)
+ throws GuacamoleException {
+
+ // Invalidate session, if it exists
+ if (!authenticationService.destroyGuacamoleSession(authToken))
+ throw new GuacamoleResourceNotFoundException("No such token.");
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/auth/TokenSessionMap.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/auth/TokenSessionMap.java b/guacamole/src/main/java/org/apache/guacamole/rest/auth/TokenSessionMap.java
new file mode 100644
index 0000000..756084a
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/auth/TokenSessionMap.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2014 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.guacamole.rest.auth;
+
+import org.apache.guacamole.GuacamoleSession;
+
+/**
+ * Represents a mapping of auth token to Guacamole session for the REST
+ * authentication system.
+ *
+ * @author James Muehlner
+ */
+public interface TokenSessionMap {
+
+ /**
+ * Registers that a user has just logged in with the specified authToken and
+ * GuacamoleSession.
+ *
+ * @param authToken The authentication token for the logged in user.
+ * @param session The GuacamoleSession for the logged in user.
+ */
+ public void put(String authToken, GuacamoleSession session);
+
+ /**
+ * Get the GuacamoleSession 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 GuacamoleSession for the given auth token, if the auth token
+ * represents a currently logged in user, null otherwise.
+ */
+ public GuacamoleSession get(String authToken);
+
+ /**
+ * Removes the GuacamoleSession associated with the given auth token.
+ *
+ * @param authToken The token to remove.
+ * @return The GuacamoleSession for the given auth token, if the auth token
+ * represents a currently logged in user, null otherwise.
+ */
+ public GuacamoleSession remove(String authToken);
+
+ /**
+ * Shuts down this session map, disallowing future sessions and reclaiming
+ * any resources.
+ */
+ public void shutdown();
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/auth/package-info.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/auth/package-info.java b/guacamole/src/main/java/org/apache/guacamole/rest/auth/package-info.java
new file mode 100644
index 0000000..d58bede
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/auth/package-info.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/**
+ * Classes related to the authentication aspect of the Guacamole REST API.
+ */
+package org.apache.guacamole.rest.auth;
+
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/connection/APIConnection.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/connection/APIConnection.java b/guacamole/src/main/java/org/apache/guacamole/rest/connection/APIConnection.java
new file mode 100644
index 0000000..0a607f7
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/connection/APIConnection.java
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2014 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.guacamole.rest.connection;
+
+import java.util.Map;
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.net.auth.Connection;
+import org.apache.guacamole.protocol.GuacamoleConfiguration;
+
+/**
+ * A simple connection to expose through the REST endpoints.
+ *
+ * @author James Muehlner
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
+public class APIConnection {
+
+ /**
+ * The name of this connection.
+ */
+ private String name;
+
+ /**
+ * The identifier of this connection.
+ */
+ private String identifier;
+
+ /**
+ * The identifier of the parent connection group for this connection.
+ */
+ private String parentIdentifier;
+
+ /**
+ * The protocol of this connection.
+ */
+ private String protocol;
+
+ /**
+ * Map of all associated parameter values, indexed by parameter name.
+ */
+ private Map<String, String> parameters;
+
+ /**
+ * Map of all associated attributes by attribute identifier.
+ */
+ private Map<String, String> attributes;
+
+ /**
+ * The count of currently active connections using this connection.
+ */
+ private int activeConnections;
+
+ /**
+ * Create an empty APIConnection.
+ */
+ public APIConnection() {}
+
+ /**
+ * Create an APIConnection from a Connection record. Parameters for the
+ * connection will not be included.
+ *
+ * @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 {
+
+ // Set connection information
+ this.name = connection.getName();
+ this.identifier = connection.getIdentifier();
+ this.parentIdentifier = connection.getParentIdentifier();
+ this.activeConnections = connection.getActiveConnections();
+
+ // Set protocol from configuration
+ GuacamoleConfiguration configuration = connection.getConfiguration();
+ this.protocol = configuration.getProtocol();
+
+ // Associate any attributes
+ this.attributes = connection.getAttributes();
+
+ }
+
+ /**
+ * 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.
+ * @param identifier The unique identifier for this connection.
+ */
+ public void setIdentifier(String identifier) {
+ this.identifier = identifier;
+ }
+
+ /**
+ * Returns the unique identifier for this connection.
+ * @return The unique identifier for this connection.
+ */
+ public String getParentIdentifier() {
+ return parentIdentifier;
+ }
+
+ /**
+ * Sets the parent connection group identifier for this connection.
+ * @param parentIdentifier The parent connection group identifier
+ * for this connection.
+ */
+ public void setParentIdentifier(String parentIdentifier) {
+ this.parentIdentifier = parentIdentifier;
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Returns the protocol for this connection.
+ * @return The protocol for this connection.
+ */
+ public String getProtocol() {
+ return protocol;
+ }
+
+ /**
+ * Sets the protocol for this connection.
+ * @param protocol protocol for this connection.
+ */
+ public void setProtocol(String protocol) {
+ this.protocol = protocol;
+ }
+
+ /**
+ * Returns the number of currently active connections using this
+ * connection.
+ *
+ * @return
+ * The number of currently active usages of this connection.
+ */
+ public int getActiveConnections() {
+ return activeConnections;
+ }
+
+ /**
+ * Set the number of currently active connections using this connection.
+ *
+ * @param activeConnections
+ * The number of currently active usages of this connection.
+ */
+ public void setActiveUsers(int activeConnections) {
+ this.activeConnections = activeConnections;
+ }
+
+ /**
+ * Returns a map of all attributes associated with this connection. Each
+ * entry key is the attribute identifier, while each value is the attribute
+ * value itself.
+ *
+ * @return
+ * The attribute map for this connection.
+ */
+ public Map<String, String> getAttributes() {
+ return attributes;
+ }
+
+ /**
+ * Sets the map of all attributes associated with this connection. Each
+ * entry key is the attribute identifier, while each value is the attribute
+ * value itself.
+ *
+ * @param attributes
+ * The attribute map for this connection.
+ */
+ public void setAttributes(Map<String, String> attributes) {
+ this.attributes = attributes;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/648a6c96/guacamole/src/main/java/org/apache/guacamole/rest/connection/APIConnectionWrapper.java
----------------------------------------------------------------------
diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/connection/APIConnectionWrapper.java b/guacamole/src/main/java/org/apache/guacamole/rest/connection/APIConnectionWrapper.java
new file mode 100644
index 0000000..a785930
--- /dev/null
+++ b/guacamole/src/main/java/org/apache/guacamole/rest/connection/APIConnectionWrapper.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2014 Glyptodon LLC
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package org.apache.guacamole.rest.connection;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.net.GuacamoleTunnel;
+import org.apache.guacamole.net.auth.Connection;
+import org.apache.guacamole.net.auth.ConnectionRecord;
+import org.apache.guacamole.protocol.GuacamoleClientInformation;
+import org.apache.guacamole.protocol.GuacamoleConfiguration;
+
+/**
+ * A wrapper to make an APIConnection look like a Connection. Useful where a
+ * org.apache.guacamole.net.auth.Connection is required.
+ *
+ * @author James Muehlner
+ */
+public class APIConnectionWrapper implements Connection {
+
+ /**
+ * The wrapped APIConnection.
+ */
+ private final APIConnection apiConnection;
+
+ /**
+ * Creates a new APIConnectionWrapper which wraps the given APIConnection
+ * as a Connection.
+ *
+ * @param apiConnection
+ * The APIConnection to wrap.
+ */
+ 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 String getParentIdentifier() {
+ return apiConnection.getParentIdentifier();
+ }
+
+ @Override
+ public void setParentIdentifier(String parentIdentifier) {
+ apiConnection.setParentIdentifier(parentIdentifier);
+ }
+
+ @Override
+ public int getActiveConnections() {
+ return apiConnection.getActiveConnections();
+ }
+
+ @Override
+ public GuacamoleConfiguration getConfiguration() {
+
+ // Create the GuacamoleConfiguration with current protocol
+ GuacamoleConfiguration configuration = new GuacamoleConfiguration();
+ configuration.setProtocol(apiConnection.getProtocol());
+
+ // Add parameters, if available
+ Map<String, String> parameters = apiConnection.getParameters();
+ if (parameters != null)
+ configuration.setParameters(parameters);
+
+ return configuration;
+ }
+
+ @Override
+ public void setConfiguration(GuacamoleConfiguration config) {
+
+ // Set protocol and parameters
+ apiConnection.setProtocol(config.getProtocol());
+ apiConnection.setParameters(config.getParameters());
+
+ }
+
+ @Override
+ public Map<String, String> getAttributes() {
+ return apiConnection.getAttributes();
+ }
+
+ @Override
+ public void setAttributes(Map<String, String> attributes) {
+ apiConnection.setAttributes(attributes);
+ }
+
+ @Override
+ public GuacamoleTunnel connect(GuacamoleClientInformation info) throws GuacamoleException {
+ throw new UnsupportedOperationException("Operation not supported.");
+ }
+
+ @Override
+ public List<? extends ConnectionRecord> getHistory() throws GuacamoleException {
+ return Collections.<ConnectionRecord>emptyList();
+ }
+
+}