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();
+    }
+    
+}