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/08/01 00:28:52 UTC

[3/7] incubator-guacamole-client git commit: GUACAMOLE-5: Implement exposure of a dynamic set of share keys as connections within a connection directory.

GUACAMOLE-5: Implement exposure of a dynamic set of share keys as connections within a connection directory.


Project: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/commit/96094a1c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/tree/96094a1c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/diff/96094a1c

Branch: refs/heads/master
Commit: 96094a1c5842b470356a35d7959fa22774e5b24f
Parents: 29f9aea
Author: Michael Jumper <mj...@apache.org>
Authored: Fri Jul 29 14:36:11 2016 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Sat Jul 30 23:11:12 2016 -0700

----------------------------------------------------------------------
 .../jdbc/sharing/ConnectionSharingService.java  |  30 +--
 .../jdbc/sharing/HashSharedConnectionMap.java   |   1 +
 .../SharedAuthenticationProviderService.java    |  38 ++--
 .../auth/jdbc/sharing/SharedConnection.java     | 168 ---------------
 .../sharing/SharedConnectionDefinition.java     | 165 --------------
 .../auth/jdbc/sharing/SharedConnectionMap.java  |   2 +
 .../auth/jdbc/sharing/SharedConnectionUser.java |  93 --------
 .../sharing/SharedConnectionUserContext.java    | 215 -------------------
 .../sharing/connection/SharedConnection.java    | 161 ++++++++++++++
 .../connection/SharedConnectionDefinition.java  | 166 ++++++++++++++
 .../connection/SharedConnectionDirectory.java   | 158 ++++++++++++++
 .../SharedRootConnectionGroup.java              | 144 +++++++++++++
 .../permission/SharedObjectPermissionSet.java   |  72 +++++++
 .../sharing/user/SharedAuthenticatedUser.java   | 105 +++++++++
 .../auth/jdbc/sharing/user/SharedUser.java      | 136 ++++++++++++
 .../jdbc/sharing/user/SharedUserContext.java    | 203 +++++++++++++++++
 .../tunnel/AbstractGuacamoleTunnelService.java  |   5 +-
 .../jdbc/tunnel/GuacamoleTunnelService.java     |   6 +-
 18 files changed, 1193 insertions(+), 675 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/96094a1c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/ConnectionSharingService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/ConnectionSharingService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/ConnectionSharingService.java
index 40de6e3..4c5877f 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/ConnectionSharingService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/ConnectionSharingService.java
@@ -25,6 +25,8 @@ import javax.servlet.http.HttpServletRequest;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.GuacamoleSecurityException;
+import org.apache.guacamole.auth.jdbc.sharing.connection.SharedConnectionDefinition;
+import org.apache.guacamole.auth.jdbc.sharing.user.SharedAuthenticatedUser;
 import org.apache.guacamole.auth.jdbc.sharingprofile.ModeledSharingProfile;
 import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileService;
 import org.apache.guacamole.auth.jdbc.tunnel.ActiveConnectionRecord;
@@ -128,11 +130,11 @@ public class ConnectionSharingService {
     }
 
     /**
-     * Returns a SharedConnectionUser (an implementation of AuthenticatedUser)
-     * if the given credentials contain a valid share key. The returned user
-     * will be associated with the single shared connection to which they have
-     * been granted temporary access. If the share key is invalid, or no share
-     * key is contained within the given credentials, null is returned.
+     * Returns a SharedAuthenticatedUser if the given credentials contain a
+     * valid share key. The returned user will be associated with the single
+     * shared connection to which they have been granted temporary access. If
+     * the share key is invalid, or no share key is contained within the given
+     * credentials, null is returned.
      *
      * @param authProvider
      *     The AuthenticationProvider on behalf of which the user is being
@@ -142,11 +144,11 @@ public class ConnectionSharingService {
      *     The credentials which are expected to contain the share key.
      *
      * @return
-     *     A SharedConnectionUser with access to a single shared connection, if
-     *     the share key within the given credentials is valid, or null if the
-     *     share key is invalid or absent.
+     *     A SharedAuthenticatedUser with access to a single shared connection,
+     *     if the share key within the given credentials is valid, or null if
+     *     the share key is invalid or absent.
      */
-    public SharedConnectionUser retrieveSharedConnectionUser(
+    public SharedAuthenticatedUser retrieveSharedConnectionUser(
             AuthenticationProvider authProvider, Credentials credentials) {
 
         // Pull associated HTTP request
@@ -159,14 +161,12 @@ public class ConnectionSharingService {
         if (shareKey == null)
             return null;
 
-        // Pull the connection definition describing the connection these
-        // credentials provide access to (if any)
-        SharedConnectionDefinition definition = connectionMap.get(shareKey);
-        if (definition == null)
+        // Validate the share key
+        if (connectionMap.get(shareKey) == null)
             return null;
 
-        // Return temporary in-memory user with access only to the shared connection
-        return new SharedConnectionUser(authProvider, definition, credentials);
+        // Return temporary in-memory user
+        return new SharedAuthenticatedUser(authProvider, credentials, shareKey);
 
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/96094a1c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/HashSharedConnectionMap.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/HashSharedConnectionMap.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/HashSharedConnectionMap.java
index ddd812b..959d931 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/HashSharedConnectionMap.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/HashSharedConnectionMap.java
@@ -21,6 +21,7 @@ package org.apache.guacamole.auth.jdbc.sharing;
 
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import org.apache.guacamole.auth.jdbc.sharing.connection.SharedConnectionDefinition;
 
 /**
  * A HashMap-based implementation of the SharedConnectionMap.

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/96094a1c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedAuthenticationProviderService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedAuthenticationProviderService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedAuthenticationProviderService.java
index cd4e6c2..ddcd929 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedAuthenticationProviderService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedAuthenticationProviderService.java
@@ -23,6 +23,8 @@ import com.google.inject.Inject;
 import com.google.inject.Provider;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.auth.jdbc.AuthenticationProviderService;
+import org.apache.guacamole.auth.jdbc.sharing.user.SharedAuthenticatedUser;
+import org.apache.guacamole.auth.jdbc.sharing.user.SharedUserContext;
 import org.apache.guacamole.net.auth.AuthenticatedUser;
 import org.apache.guacamole.net.auth.AuthenticationProvider;
 import org.apache.guacamole.net.auth.Credentials;
@@ -31,8 +33,8 @@ import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsExce
 
 /**
  * Service which authenticates users based on share keys and provides for the
- * creation of corresponding. The created UserContext objects are restricted to
- * the connections associated with those share keys via a common
+ * creation of corresponding UserContexts. The created UserContext objects are
+ * restricted to the connections associated with those share keys via a common
  * ConnectionSharingService.
  *
  * @author Michael Jumper
@@ -40,10 +42,10 @@ import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsExce
 public class SharedAuthenticationProviderService implements AuthenticationProviderService {
 
     /**
-     * Provider for retrieving SharedConnectionUserContext instances.
+     * Provider for retrieving SharedUserContext instances.
      */
     @Inject
-    private Provider<SharedConnectionUserContext> sharedUserContextProvider;
+    private Provider<SharedUserContext> sharedUserContextProvider;
 
     /**
      * Service for sharing active connections.
@@ -66,19 +68,29 @@ public class SharedAuthenticationProviderService implements AuthenticationProvid
     }
 
     @Override
-    public org.apache.guacamole.net.auth.UserContext getUserContext(
+    public SharedUserContext getUserContext(
             AuthenticationProvider authenticationProvider,
             AuthenticatedUser authenticatedUser) throws GuacamoleException {
 
-        // Produce sharing-specific user context if this is the user of a shared connection
-        if (authenticatedUser instanceof SharedConnectionUser) {
-            SharedConnectionUserContext context = sharedUserContextProvider.get();
-            context.init((SharedConnectionUser) authenticatedUser);
-            return context;
-        }
+        // Obtain a reference to a correct AuthenticatedUser which can be used
+        // for accessing shared connections
+        SharedAuthenticatedUser sharedAuthenticatedUser;
+        if (authenticatedUser instanceof SharedAuthenticatedUser)
+            sharedAuthenticatedUser = (SharedAuthenticatedUser) authenticatedUser;
+        else
+            sharedAuthenticatedUser = new SharedAuthenticatedUser(authenticatedUser);
 
-        // No shared connections otherwise
-        return null;
+        // Produce empty user context for known-authenticated user
+        SharedUserContext context = sharedUserContextProvider.get();
+        context.init(authenticationProvider, sharedAuthenticatedUser);
+
+        // Add the shared connection associated with the originally-provided
+        // share key (if any)
+        String shareKey = sharedAuthenticatedUser.getShareKey();
+        if (shareKey != null)
+            context.registerShareKey(shareKey);
+
+        return context;
 
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/96094a1c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnection.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnection.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnection.java
deleted file mode 100644
index 18862dc..0000000
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnection.java
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.guacamole.auth.jdbc.sharing;
-
-import com.google.inject.Inject;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.auth.jdbc.connectiongroup.RootConnectionGroup;
-import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
-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 Connection which joins an active connection, limited by restrictions
- * defined by a sharing profile.
- *
- * @author Michael Jumper
- */
-public class SharedConnection implements Connection {
-
-    /**
-     * Service for establishing tunnels to Guacamole connections.
-     */
-    @Inject
-    private GuacamoleTunnelService tunnelService;
-
-    /**
-     * Randomly-generated unique identifier, guaranteeing this shared connection
-     * does not duplicate the identifying information of the underlying
-     * connection being shared.
-     */
-    private final String identifier = UUID.randomUUID().toString();
-
-    /**
-     * The user that successfully authenticated to obtain access to this
-     * SharedConnection.
-     */
-    private SharedConnectionUser user;
-
-    /**
-     * The SharedConnectionDefinition dictating the connection being shared and
-     * any associated restrictions.
-     */
-    private SharedConnectionDefinition definition;
-
-    /**
-     * Creates a new SharedConnection which can be used to join the connection
-     * described by the given SharedConnectionDefinition.
-     *
-     * @param user
-     *     The user that successfully authenticated to obtain access to this
-     *     SharedConnection.
-     *
-     * @param definition
-     *     The SharedConnectionDefinition dictating the connection being shared
-     *     and any associated restrictions.
-     */
-    public void init(SharedConnectionUser user, SharedConnectionDefinition definition) {
-        this.user = user;
-        this.definition = definition;
-    }
-
-    @Override
-    public String getIdentifier() {
-        return identifier;
-    }
-
-    @Override
-    public void setIdentifier(String identifier) {
-        throw new UnsupportedOperationException("Shared connections are immutable.");
-    }
-
-    @Override
-    public String getName() {
-        return definition.getSharingProfile().getName();
-    }
-
-    @Override
-    public void setName(String name) {
-        throw new UnsupportedOperationException("Shared connections are immutable.");
-    }
-
-    @Override
-    public String getParentIdentifier() {
-        return RootConnectionGroup.IDENTIFIER;
-    }
-
-    @Override
-    public void setParentIdentifier(String parentIdentifier) {
-        throw new UnsupportedOperationException("Shared connections are immutable.");
-    }
-
-    @Override
-    public GuacamoleConfiguration getConfiguration() {
-
-        // Pull the connection being shared
-        Connection primaryConnection = definition.getActiveConnection().getConnection();
-
-        // Construct a skeletal configuration that exposes only the protocol in use
-        GuacamoleConfiguration config = new GuacamoleConfiguration();
-        config.setProtocol(primaryConnection.getConfiguration().getProtocol());
-        return config;
-
-    }
-
-    @Override
-    public void setConfiguration(GuacamoleConfiguration config) {
-        throw new UnsupportedOperationException("Shared connections are immutable.");
-    }
-
-    @Override
-    public GuacamoleTunnel connect(GuacamoleClientInformation info)
-            throws GuacamoleException {
-        return tunnelService.getGuacamoleTunnel(user, definition, info);
-    }
-
-    @Override
-    public Map<String, String> getAttributes() {
-        return Collections.<String, String>emptyMap();
-    }
-
-    @Override
-    public void setAttributes(Map<String, String> attributes) {
-        // Do nothing - no attributes supported
-    }
-
-    @Override
-    public List<? extends ConnectionRecord> getHistory()
-            throws GuacamoleException {
-        return Collections.<ConnectionRecord>emptyList();
-    }
-
-    @Override
-    public Set<String> getSharingProfileIdentifiers()
-            throws GuacamoleException {
-        return Collections.<String>emptySet();
-    }
-
-    @Override
-    public int getActiveConnections() {
-        return 0;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/96094a1c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnectionDefinition.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnectionDefinition.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnectionDefinition.java
deleted file mode 100644
index d4a6b7e..0000000
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnectionDefinition.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.guacamole.auth.jdbc.sharing;
-
-import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.auth.jdbc.sharingprofile.ModeledSharingProfile;
-import org.apache.guacamole.auth.jdbc.tunnel.ActiveConnectionRecord;
-import org.apache.guacamole.net.GuacamoleTunnel;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Defines the semantics/restrictions of a shared connection by associating an
- * active connection with a sharing profile. The sharing profile defines the
- * access provided to users of the shared active connection through its
- * connection parameters.
- *
- * @author Michael Jumper
- */
-public class SharedConnectionDefinition {
-
-    /**
-     * Logger for this class.
-     */
-    private final Logger logger = LoggerFactory.getLogger(SharedConnectionDefinition.class);
-
-    /**
-     * The active connection being shared.
-     */
-    private final ActiveConnectionRecord activeConnection;
-
-    /**
-     * The sharing profile which dictates the level of access provided to a user
-     * of the shared connection.
-     */
-    private final ModeledSharingProfile sharingProfile;
-
-    /**
-     * The unique key with which a user may access the shared connection.
-     */
-    private final String shareKey;
-
-    /**
-     * Manager which tracks all tunnels associated with this shared connection
-     * definition. All tunnels registered with this manager will be
-     * automatically closed once the manager is invalidated.
-     */
-    private final SharedObjectManager<GuacamoleTunnel> tunnels =
-            new SharedObjectManager<GuacamoleTunnel>() {
-
-        @Override
-        protected void cleanup(GuacamoleTunnel tunnel) {
-
-            try {
-                tunnel.close();
-            }
-            catch (GuacamoleException e) {
-                logger.debug("Unable to close tunnel of shared connection.", e);
-            }
-
-        }
-
-    };
-
-    /**
-     * Creates a new SharedConnectionDefinition which describes an active
-     * connection that can be joined, including the restrictions dictated by a
-     * given sharing profile.
-     *
-     * @param activeConnection
-     *     The active connection being shared.
-     *
-     * @param sharingProfile
-     *     A sharing profile whose associated parameters dictate the level of
-     *     access provided to the shared connection.
-     *
-     * @param shareKey
-     *     The unique key with which a user may access the shared connection.
-     */
-    public SharedConnectionDefinition(ActiveConnectionRecord activeConnection,
-            ModeledSharingProfile sharingProfile, String shareKey) {
-        this.activeConnection = activeConnection;
-        this.sharingProfile = sharingProfile;
-        this.shareKey = shareKey;
-    }
-
-    /**
-     * Returns the ActiveConnectionRecord of the actual in-progress connection
-     * being shared.
-     *
-     * @return
-     *     The ActiveConnectionRecord being shared.
-     */
-    public ActiveConnectionRecord getActiveConnection() {
-        return activeConnection;
-    }
-
-    /**
-     * Returns the ModeledSharingProfile whose associated parameters dictate the
-     * level of access granted to users of the shared connection.
-     *
-     * @return
-     *     A ModeledSharingProfile whose associated parameters dictate the
-     *     level of access granted to users of the shared connection.
-     */
-    public ModeledSharingProfile getSharingProfile() {
-        return sharingProfile;
-    }
-
-    /**
-     * Returns the unique key with which a user may access the shared
-     * connection.
-     *
-     * @return
-     *     The unique key with which a user may access the shared connection.
-     */
-    public String getShareKey() {
-        return shareKey;
-    }
-
-    /**
-     * Registers the given tunnel with this SharedConnectionDefinition, such
-     * that the tunnel is automatically closed when this
-     * SharedConnectionDefinition is invalidated. For shared connections to be
-     * properly closed when the associated share key ceases being valid, the
-     * tunnels resulting from the use of the share key MUST be registered to the
-     * SharedConnectionDefinition associated with that share key.
-     *
-     * @param tunnel
-     *     The tunnel which should automatically be closed when this
-     *     SharedConnectionDefinition is invalidated.
-     */
-    public void registerTunnel(GuacamoleTunnel tunnel) {
-        tunnels.register(tunnel);
-    }
-
-    /**
-     * Invalidates this SharedConnectionDefinition and closes all registered
-     * tunnels. If any additional tunnels are registered after this function is
-     * invoked, those tunnels will be immediately closed. This function MUST be
-     * invoked when the share key associated with this
-     * SharedConnectionDefinition will no longer be used.
-     */
-    public void invalidate() {
-        tunnels.invalidate();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/96094a1c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnectionMap.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnectionMap.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnectionMap.java
index 29bce50..e33bc2d 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnectionMap.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnectionMap.java
@@ -19,6 +19,8 @@
 
 package org.apache.guacamole.auth.jdbc.sharing;
 
+import org.apache.guacamole.auth.jdbc.sharing.connection.SharedConnectionDefinition;
+
 /**
  * Represents a mapping between share keys and the Guacamole connection being
  * shared.

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/96094a1c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnectionUser.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnectionUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnectionUser.java
deleted file mode 100644
index 125628a..0000000
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnectionUser.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.guacamole.auth.jdbc.sharing;
-
-import java.util.UUID;
-import org.apache.guacamole.auth.jdbc.user.RemoteAuthenticatedUser;
-import org.apache.guacamole.net.auth.AuthenticationProvider;
-import org.apache.guacamole.net.auth.Credentials;
-
-/**
- * A temporary user who has authenticated using a share key and thus has
- * restricted access to a single shared connection.
- *
- * @author Michael Jumper
- */
-public class SharedConnectionUser extends RemoteAuthenticatedUser {
-
-    /**
-     * The single shared connection to which this user has access.
-     */
-    private final SharedConnectionDefinition definition;
-
-    /**
-     * An arbitrary identifier guaranteed to be unique across users. Note that
-     * because Guacamole users the AuthenticatedUser's identifier as the means
-     * of determining overall user identity and aggregating data across
-     * multiple extensions, this identifier MUST NOT match the identifier of
-     * any possibly existing user (or else the user may unexpectedly gain
-     * access to another identically-named user's data).
-     */
-    private final String identifier = UUID.randomUUID().toString();
-
-    /**
-     * Creates a new SharedConnectionUser with access solely to connection
-     * described by the given SharedConnectionDefinition.
-     *
-     * @param authenticationProvider
-     *     The AuthenticationProvider that has authenticated the given user.
-     *
-     * @param definition
-     *     The SharedConnectionDefinition describing the connection that this
-     *     user should have access to, along with any associated restrictions.
-     *
-     * @param credentials 
-     *     The credentials given by the user when they authenticated.
-     */
-    public SharedConnectionUser(AuthenticationProvider authenticationProvider,
-           SharedConnectionDefinition definition, Credentials credentials) {
-        super(authenticationProvider, credentials);
-        this.definition = definition;
-    }
-
-    @Override
-    public String getIdentifier() {
-        return identifier;
-    }
-
-    @Override
-    public void setIdentifier(String identifier) {
-        throw new UnsupportedOperationException("Shared connection users are immutable");
-    }
-
-    /**
-     * Returns the SharedConnectionDefinition which describes the connection
-     * that this user should have access to, along with any associated
-     * restrictions.
-     *
-     * @return
-     *     The SharedConnectionDefinition describing the connection that this
-     *     user should have access to, along with any associated restrictions.
-     */
-    public SharedConnectionDefinition getSharedConnectionDefinition() {
-        return definition;
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/96094a1c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnectionUserContext.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnectionUserContext.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnectionUserContext.java
deleted file mode 100644
index 67d70c6..0000000
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/SharedConnectionUserContext.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.guacamole.auth.jdbc.sharing;
-
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import java.util.Collection;
-import java.util.Collections;
-import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.form.Form;
-import org.apache.guacamole.net.auth.ActiveConnection;
-import org.apache.guacamole.net.auth.AuthenticationProvider;
-import org.apache.guacamole.net.auth.Connection;
-import org.apache.guacamole.net.auth.ConnectionGroup;
-import org.apache.guacamole.net.auth.ConnectionRecordSet;
-import org.apache.guacamole.net.auth.Directory;
-import org.apache.guacamole.net.auth.SharingProfile;
-import org.apache.guacamole.net.auth.User;
-import org.apache.guacamole.net.auth.UserContext;
-import org.apache.guacamole.net.auth.simple.SimpleConnectionDirectory;
-import org.apache.guacamole.net.auth.simple.SimpleConnectionGroup;
-import org.apache.guacamole.net.auth.simple.SimpleConnectionGroupDirectory;
-import org.apache.guacamole.net.auth.simple.SimpleConnectionRecordSet;
-import org.apache.guacamole.net.auth.simple.SimpleDirectory;
-import org.apache.guacamole.net.auth.simple.SimpleUser;
-import org.apache.guacamole.net.auth.simple.SimpleUserDirectory;
-
-/**
- * The user context of a SharedConnectionUser, providing access ONLY to the
- * user themselves, the single SharedConnection associated with that user, and
- * an internal root connection group containing only that single
- * SharedConnection.
- *
- * @author Michael Jumper
- */
-public class SharedConnectionUserContext implements UserContext {
-
-    /**
-     * Provider for retrieving SharedConnection instances.
-     */
-    @Inject
-    private Provider<SharedConnection> connectionProvider;
-
-    /**
-     * The AuthenticationProvider that created this SharedConnectionUserContext.
-     */
-    private AuthenticationProvider authProvider;
-
-    /**
-     * The user whose level of access is represented by this user context.
-     */
-    private User self;
-
-    /**
-     * A directory of all connections visible to the user for whom this user
-     * context was created.
-     */
-    private Directory<Connection> connectionDirectory;
-
-    /**
-     * A directory of all connection groups visible to the user for whom this
-     * user context was created.
-     */
-    private Directory<ConnectionGroup> connectionGroupDirectory;
-
-    /**
-     * A directory of all users visible to the user for whom this user context
-     * was created.
-     */
-    private Directory<User> userDirectory;
-
-    /**
-     * The root connection group of the hierarchy containing all connections
-     * and connection groups visible to the user for whom this user context was
-     * created.
-     */
-    private ConnectionGroup rootGroup;
-
-    /**
-     * Creates a new SharedConnectionUserContext which provides access ONLY to
-     * the given user, the single SharedConnection associated with that user,
-     * and an internal root connection group containing only that single
-     * SharedConnection.
-     *
-     * @param user
-     *     The SharedConnectionUser for whom this SharedConnectionUserContext
-     *     is being created.
-     */
-    public void init(SharedConnectionUser user) {
-
-        // Get the definition of the shared connection
-        SharedConnectionDefinition definition =
-                user.getSharedConnectionDefinition();
-
-        // Create a single shared connection accessible by the user
-        SharedConnection connection = connectionProvider.get();
-        connection.init(user, definition);
-
-        // Build list of all accessible connection identifiers
-        Collection<String> connectionIdentifiers =
-                Collections.singletonList(connection.getIdentifier());
-
-        // Associate the originating authentication provider
-        this.authProvider = user.getAuthenticationProvider();
-
-        // The connection directory should contain only the shared connection
-        this.connectionDirectory = new SimpleConnectionDirectory(
-                Collections.<Connection>singletonList(connection));
-
-        // The user should have access only to the shared connection and himself
-        this.self = new SimpleUser(user.getIdentifier(),
-                Collections.<String>singletonList(user.getIdentifier()),
-                connectionIdentifiers,
-                Collections.<String>emptyList());
-
-        // The root group contains only the shared connection
-        String rootIdentifier = connection.getParentIdentifier();
-        this.rootGroup = new SimpleConnectionGroup(rootIdentifier, rootIdentifier,
-                connectionIdentifiers, Collections.<String>emptyList());
-
-        // The connection group directory contains only the root group
-        this.connectionGroupDirectory = new SimpleConnectionGroupDirectory(
-                Collections.singletonList(this.rootGroup));
-
-        // The user directory contains only this user
-        this.userDirectory = new SimpleUserDirectory(this.self);
-
-    }
-
-    @Override
-    public User self() {
-        return self;
-    }
-
-    @Override
-    public AuthenticationProvider getAuthenticationProvider() {
-        return authProvider;
-    }
-
-    @Override
-    public Directory<User> getUserDirectory() {
-        return userDirectory;
-    }
-
-    @Override
-    public Directory<Connection> getConnectionDirectory()
-            throws GuacamoleException {
-        return connectionDirectory;
-    }
-
-    @Override
-    public Directory<ConnectionGroup> getConnectionGroupDirectory() {
-        return connectionGroupDirectory;
-    }
-
-    @Override
-    public Directory<ActiveConnection> getActiveConnectionDirectory()
-            throws GuacamoleException {
-        return new SimpleDirectory<ActiveConnection>();
-    }
-
-    @Override
-    public Directory<SharingProfile> getSharingProfileDirectory()
-            throws GuacamoleException {
-        return new SimpleDirectory<SharingProfile>();
-    }
-
-    @Override
-    public ConnectionRecordSet getConnectionHistory() {
-        return new SimpleConnectionRecordSet();
-    }
-
-    @Override
-    public ConnectionGroup getRootConnectionGroup() {
-        return rootGroup;
-    }
-
-    @Override
-    public Collection<Form> getUserAttributes() {
-        return Collections.<Form>emptyList();
-    }
-
-    @Override
-    public Collection<Form> getConnectionAttributes() {
-        return Collections.<Form>emptyList();
-    }
-
-    @Override
-    public Collection<Form> getConnectionGroupAttributes() {
-        return Collections.<Form>emptyList();
-    }
-
-    @Override
-    public Collection<Form> getSharingProfileAttributes() {
-        return Collections.<Form>emptyList();
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/96094a1c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connection/SharedConnection.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connection/SharedConnection.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connection/SharedConnection.java
new file mode 100644
index 0000000..9ced9c7
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connection/SharedConnection.java
@@ -0,0 +1,161 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.sharing.connection;
+
+import com.google.inject.Inject;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.sharing.connectiongroup.SharedRootConnectionGroup;
+import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
+import org.apache.guacamole.auth.jdbc.user.RemoteAuthenticatedUser;
+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 Connection which joins an active connection, limited by restrictions
+ * defined by a sharing profile.
+ *
+ * @author Michael Jumper
+ */
+public class SharedConnection implements Connection {
+
+    /**
+     * Service for establishing tunnels to Guacamole connections.
+     */
+    @Inject
+    private GuacamoleTunnelService tunnelService;
+
+    /**
+     * The user that successfully authenticated to obtain access to this
+     * SharedConnection.
+     */
+    private RemoteAuthenticatedUser user;
+
+    /**
+     * The SharedConnectionDefinition dictating the connection being shared and
+     * any associated restrictions.
+     */
+    private SharedConnectionDefinition definition;
+
+    /**
+     * Creates a new SharedConnection which can be used to join the connection
+     * described by the given SharedConnectionDefinition.
+     *
+     * @param user
+     *     The user that successfully authenticated to obtain access to this
+     *     SharedConnection.
+     *
+     * @param definition
+     *     The SharedConnectionDefinition dictating the connection being shared
+     *     and any associated restrictions.
+     */
+    public void init(RemoteAuthenticatedUser user, SharedConnectionDefinition definition) {
+        this.user = user;
+        this.definition = definition;
+    }
+
+    @Override
+    public String getIdentifier() {
+        return definition.getShareKey();
+    }
+
+    @Override
+    public void setIdentifier(String identifier) {
+        throw new UnsupportedOperationException("Shared connections are immutable.");
+    }
+
+    @Override
+    public String getName() {
+        return definition.getSharingProfile().getName();
+    }
+
+    @Override
+    public void setName(String name) {
+        throw new UnsupportedOperationException("Shared connections are immutable.");
+    }
+
+    @Override
+    public String getParentIdentifier() {
+        return SharedRootConnectionGroup.IDENTIFIER;
+    }
+
+    @Override
+    public void setParentIdentifier(String parentIdentifier) {
+        throw new UnsupportedOperationException("Shared connections are immutable.");
+    }
+
+    @Override
+    public GuacamoleConfiguration getConfiguration() {
+
+        // Pull the connection being shared
+        Connection primaryConnection = definition.getActiveConnection().getConnection();
+
+        // Construct a skeletal configuration that exposes only the protocol in use
+        GuacamoleConfiguration config = new GuacamoleConfiguration();
+        config.setProtocol(primaryConnection.getConfiguration().getProtocol());
+        return config;
+
+    }
+
+    @Override
+    public void setConfiguration(GuacamoleConfiguration config) {
+        throw new UnsupportedOperationException("Shared connections are immutable.");
+    }
+
+    @Override
+    public GuacamoleTunnel connect(GuacamoleClientInformation info)
+            throws GuacamoleException {
+        return tunnelService.getGuacamoleTunnel(user, definition, info);
+    }
+
+    @Override
+    public Map<String, String> getAttributes() {
+        return Collections.<String, String>emptyMap();
+    }
+
+    @Override
+    public void setAttributes(Map<String, String> attributes) {
+        // Do nothing - no attributes supported
+    }
+
+    @Override
+    public List<? extends ConnectionRecord> getHistory()
+            throws GuacamoleException {
+        return Collections.<ConnectionRecord>emptyList();
+    }
+
+    @Override
+    public Set<String> getSharingProfileIdentifiers()
+            throws GuacamoleException {
+        return Collections.<String>emptySet();
+    }
+
+    @Override
+    public int getActiveConnections() {
+        return 0;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/96094a1c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connection/SharedConnectionDefinition.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connection/SharedConnectionDefinition.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connection/SharedConnectionDefinition.java
new file mode 100644
index 0000000..bceda25
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connection/SharedConnectionDefinition.java
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.sharing.connection;
+
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.sharing.SharedObjectManager;
+import org.apache.guacamole.auth.jdbc.sharingprofile.ModeledSharingProfile;
+import org.apache.guacamole.auth.jdbc.tunnel.ActiveConnectionRecord;
+import org.apache.guacamole.net.GuacamoleTunnel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Defines the semantics/restrictions of a shared connection by associating an
+ * active connection with a sharing profile. The sharing profile defines the
+ * access provided to users of the shared active connection through its
+ * connection parameters.
+ *
+ * @author Michael Jumper
+ */
+public class SharedConnectionDefinition {
+
+    /**
+     * Logger for this class.
+     */
+    private final Logger logger = LoggerFactory.getLogger(SharedConnectionDefinition.class);
+
+    /**
+     * The active connection being shared.
+     */
+    private final ActiveConnectionRecord activeConnection;
+
+    /**
+     * The sharing profile which dictates the level of access provided to a user
+     * of the shared connection.
+     */
+    private final ModeledSharingProfile sharingProfile;
+
+    /**
+     * The unique key with which a user may access the shared connection.
+     */
+    private final String shareKey;
+
+    /**
+     * Manager which tracks all tunnels associated with this shared connection
+     * definition. All tunnels registered with this manager will be
+     * automatically closed once the manager is invalidated.
+     */
+    private final SharedObjectManager<GuacamoleTunnel> tunnels =
+            new SharedObjectManager<GuacamoleTunnel>() {
+
+        @Override
+        protected void cleanup(GuacamoleTunnel tunnel) {
+
+            try {
+                tunnel.close();
+            }
+            catch (GuacamoleException e) {
+                logger.debug("Unable to close tunnel of shared connection.", e);
+            }
+
+        }
+
+    };
+
+    /**
+     * Creates a new SharedConnectionDefinition which describes an active
+     * connection that can be joined, including the restrictions dictated by a
+     * given sharing profile.
+     *
+     * @param activeConnection
+     *     The active connection being shared.
+     *
+     * @param sharingProfile
+     *     A sharing profile whose associated parameters dictate the level of
+     *     access provided to the shared connection.
+     *
+     * @param shareKey
+     *     The unique key with which a user may access the shared connection.
+     */
+    public SharedConnectionDefinition(ActiveConnectionRecord activeConnection,
+            ModeledSharingProfile sharingProfile, String shareKey) {
+        this.activeConnection = activeConnection;
+        this.sharingProfile = sharingProfile;
+        this.shareKey = shareKey;
+    }
+
+    /**
+     * Returns the ActiveConnectionRecord of the actual in-progress connection
+     * being shared.
+     *
+     * @return
+     *     The ActiveConnectionRecord being shared.
+     */
+    public ActiveConnectionRecord getActiveConnection() {
+        return activeConnection;
+    }
+
+    /**
+     * Returns the ModeledSharingProfile whose associated parameters dictate the
+     * level of access granted to users of the shared connection.
+     *
+     * @return
+     *     A ModeledSharingProfile whose associated parameters dictate the
+     *     level of access granted to users of the shared connection.
+     */
+    public ModeledSharingProfile getSharingProfile() {
+        return sharingProfile;
+    }
+
+    /**
+     * Returns the unique key with which a user may access the shared
+     * connection.
+     *
+     * @return
+     *     The unique key with which a user may access the shared connection.
+     */
+    public String getShareKey() {
+        return shareKey;
+    }
+
+    /**
+     * Registers the given tunnel with this SharedConnectionDefinition, such
+     * that the tunnel is automatically closed when this
+     * SharedConnectionDefinition is invalidated. For shared connections to be
+     * properly closed when the associated share key ceases being valid, the
+     * tunnels resulting from the use of the share key MUST be registered to the
+     * SharedConnectionDefinition associated with that share key.
+     *
+     * @param tunnel
+     *     The tunnel which should automatically be closed when this
+     *     SharedConnectionDefinition is invalidated.
+     */
+    public void registerTunnel(GuacamoleTunnel tunnel) {
+        tunnels.register(tunnel);
+    }
+
+    /**
+     * Invalidates this SharedConnectionDefinition and closes all registered
+     * tunnels. If any additional tunnels are registered after this function is
+     * invoked, those tunnels will be immediately closed. This function MUST be
+     * invoked when the share key associated with this
+     * SharedConnectionDefinition will no longer be used.
+     */
+    public void invalidate() {
+        tunnels.invalidate();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/96094a1c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connection/SharedConnectionDirectory.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connection/SharedConnectionDirectory.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connection/SharedConnectionDirectory.java
new file mode 100644
index 0000000..441203c
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connection/SharedConnectionDirectory.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.sharing.connection;
+
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.GuacamoleSecurityException;
+import org.apache.guacamole.auth.jdbc.sharing.SharedConnectionMap;
+import org.apache.guacamole.auth.jdbc.user.RemoteAuthenticatedUser;
+import org.apache.guacamole.net.auth.Connection;
+import org.apache.guacamole.net.auth.Directory;
+
+/**
+ * A Directory implementation which exposes an explicitly-registered set of
+ * share keys as connections. Only explicitly-registered share keys are
+ * accessible a SharedConnectionDirectory.
+ *
+ * @author Michael Jumper
+ */
+public class SharedConnectionDirectory implements Directory<Connection> {
+
+    /**
+     * Map of all currently-shared connections.
+     */
+    @Inject
+    private SharedConnectionMap connectionMap;
+
+    /**
+     * Provider for retrieving SharedConnection instances.
+     */
+    @Inject
+    private Provider<SharedConnection> connectionProvider;
+
+    /**
+     * The user associated with the UserContext that contains this directory.
+     */
+    private RemoteAuthenticatedUser currentUser;
+
+    /**
+     * The set of share keys that have been explicitly registered. In general,
+     * only valid share keys will be present here, but invalid keys are only
+     * removed after an attempt to retrieve those keys has been made.
+     */
+    private final Set<String> shareKeys =
+            Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>());
+
+    /**
+     * Creates a new SharedConnectionDirectory which exposes share keys as
+     * connections. Only explicitly-registered and valid share keys will be
+     * accessible.
+     *
+     * @param currentUser
+     *     The user associated with the UserContext that will contain this
+     *     directory.
+     */
+    public void init(RemoteAuthenticatedUser currentUser) {
+        this.currentUser = currentUser;
+    }
+
+    /**
+     * Registers a new share key such that the connection associated with that
+     * share key is accessible through this directory. The share key will be
+     * automatically de-registered when it is no longer valid.
+     *
+     * @param shareKey
+     *     The share key to register.
+     */
+    public void registerShareKey(String shareKey) {
+        shareKeys.add(shareKey);
+    }
+
+    @Override
+    public Connection get(String identifier) throws GuacamoleException {
+
+        // Allow access only to registered share keys
+        if (!shareKeys.contains(identifier))
+            return null;
+
+        // Retrieve the connection definition associated with that share key,
+        // cleaning up the internally-stored share key if it's no longer valid
+        SharedConnectionDefinition connectionDefinition = connectionMap.get(identifier);
+        if (connectionDefinition == null) {
+            shareKeys.remove(identifier);
+            return null;
+        }
+
+        // Return a Connection which wraps that connection definition
+        SharedConnection connection = connectionProvider.get();
+        connection.init(currentUser, connectionDefinition);
+        return connection;
+
+    }
+
+    @Override
+    public Collection<Connection> getAll(Collection<String> identifiers)
+            throws GuacamoleException {
+
+        // Create collection with enough backing space to contain one
+        // connection per identifier given
+        Collection<Connection> matchingConnections =
+                new ArrayList<Connection>(identifiers.size());
+
+        // Add all connnections which exist according to get()
+        for (String identifier : identifiers) {
+            Connection connection = get(identifier);
+            if (connection != null)
+                matchingConnections.add(connection);
+        }
+
+        return Collections.unmodifiableCollection(matchingConnections);
+
+    }
+
+    @Override
+    public Set<String> getIdentifiers() throws GuacamoleException {
+        return Collections.unmodifiableSet(shareKeys);
+    }
+
+    @Override
+    public void add(Connection object) throws GuacamoleException {
+        throw new GuacamoleSecurityException("Permission denied.");
+    }
+
+    @Override
+    public void update(Connection object) throws GuacamoleException {
+        throw new GuacamoleSecurityException("Permission denied.");
+    }
+
+    @Override
+    public void remove(String identifier) throws GuacamoleException {
+        throw new GuacamoleSecurityException("Permission denied.");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/96094a1c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connectiongroup/SharedRootConnectionGroup.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connectiongroup/SharedRootConnectionGroup.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connectiongroup/SharedRootConnectionGroup.java
new file mode 100644
index 0000000..0a79230
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/connectiongroup/SharedRootConnectionGroup.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.sharing.connectiongroup;
+
+import org.apache.guacamole.auth.jdbc.sharing.user.SharedUserContext;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.GuacamoleSecurityException;
+import org.apache.guacamole.net.GuacamoleTunnel;
+import org.apache.guacamole.net.auth.Connection;
+import org.apache.guacamole.net.auth.ConnectionGroup;
+import org.apache.guacamole.net.auth.Directory;
+import org.apache.guacamole.protocol.GuacamoleClientInformation;
+
+/**
+ * A ConnectionGroup implementation which contains all connections accessible
+ * via a given SharedUserContext. The identifier of a SharedRootConnectionGroup
+ * is statically defined, and all Connections which are intended to be contained
+ * within an instance of SharedRootConnectionGroup MUST return that identifier
+ * via getParentIdentifier().
+ *
+ * @author Michael Jumper
+ */
+public class SharedRootConnectionGroup implements ConnectionGroup {
+
+    /**
+     * The identifier of the root connection group. All Connections which are
+     * intended to be contained within an instance of SharedRootConnectionGroup
+     * MUST return this identifier via getParentIdentifier().
+     */
+    public static final String IDENTIFIER = "ROOT";
+
+    /**
+     * The SharedUserContext through which this connection group is accessible.
+     */
+    private final SharedUserContext userContext;
+
+    /**
+     * Creates a new SharedRootConnectionGroup which contains all connections
+     * accessible via the given SharedUserContext. The SharedRootConnectionGroup
+     * is backed by the SharedUserContext, and any changes to the connections
+     * within the SharedUserContext are immediately reflected in the
+     * SharedRootConnectionGroup.
+     *
+     * @param userContext
+     *     The SharedUserContext which should back the new
+     *     SharedRootConnectionGroup.
+     */
+    public SharedRootConnectionGroup(SharedUserContext userContext) {
+        this.userContext = userContext;
+    }
+
+    @Override
+    public String getIdentifier() {
+        return IDENTIFIER;
+    }
+
+    @Override
+    public void setIdentifier(String identifier) {
+        throw new UnsupportedOperationException("The root group is immutable.");
+    }
+
+    @Override
+    public String getName() {
+        return IDENTIFIER;
+    }
+
+    @Override
+    public void setName(String name) {
+        throw new UnsupportedOperationException("The root group is immutable.");
+    }
+
+    @Override
+    public String getParentIdentifier() {
+        return IDENTIFIER;
+    }
+
+    @Override
+    public void setParentIdentifier(String parentIdentifier) {
+        throw new UnsupportedOperationException("The root group is immutable.");
+    }
+
+    @Override
+    public GuacamoleTunnel connect(GuacamoleClientInformation info)
+            throws GuacamoleException {
+        throw new GuacamoleSecurityException("Permission denied.");
+    }
+
+    @Override
+    public Map<String, String> getAttributes() {
+        return Collections.<String, String>emptyMap();
+    }
+
+    @Override
+    public void setAttributes(Map<String, String> attributes) {
+        // Do nothing - no attributes supported
+    }
+
+    @Override
+    public int getActiveConnections() {
+        return 0;
+    }
+
+    @Override
+    public void setType(Type type) {
+        throw new UnsupportedOperationException("The root group is immutable.");
+    }
+
+    @Override
+    public Type getType() {
+        return Type.BALANCING;
+    }
+
+    @Override
+    public Set<String> getConnectionIdentifiers() throws GuacamoleException {
+        Directory<Connection> connectionDirectory = userContext.getConnectionDirectory();
+        return connectionDirectory.getIdentifiers();
+    }
+
+    @Override
+    public Set<String> getConnectionGroupIdentifiers() throws GuacamoleException {
+        return Collections.<String>emptySet();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/96094a1c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/permission/SharedObjectPermissionSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/permission/SharedObjectPermissionSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/permission/SharedObjectPermissionSet.java
new file mode 100644
index 0000000..18652bf
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/permission/SharedObjectPermissionSet.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.sharing.permission;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import org.apache.guacamole.net.auth.permission.ObjectPermission;
+import org.apache.guacamole.net.auth.simple.SimpleObjectPermissionSet;
+
+/**
+ * An immutable ObjectPermissionSet which defines only READ permissions for a
+ * fixed set of identifiers.
+ *
+ * @author Michael Jumper
+ */
+public class SharedObjectPermissionSet extends SimpleObjectPermissionSet {
+
+    /**
+     * Returns a new Set of ObjectPermissions defining READ access for each of
+     * the given identifiers.
+     *
+     * @param identifiers
+     *     The identifiers of the objects for which READ permission should be
+     *     granted.
+     *
+     * @return
+     *     A new Set of ObjectPermissions granting READ access for each of the
+     *     given identifiers.
+     */
+    private static Set<ObjectPermission> getPermissions(Collection<String> identifiers) {
+
+        // Include one READ permission for each of the given identifiers
+        Set<ObjectPermission> permissions = new HashSet<ObjectPermission>();
+        for (String identifier : identifiers)
+            permissions.add(new ObjectPermission(ObjectPermission.Type.READ, identifier));
+
+        return permissions;
+
+    }
+
+    /**
+     * Creates a new SharedObjectPermissionSet which grants read-only access to
+     * the objects having the given identifiers. No other permissions are
+     * granted.
+     *
+     * @param identifiers
+     *     The identifiers of the objects for which READ access should be
+     *     granted.
+     */
+    public SharedObjectPermissionSet(Collection<String> identifiers) {
+        super(getPermissions(identifiers));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/96094a1c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedAuthenticatedUser.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedAuthenticatedUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedAuthenticatedUser.java
new file mode 100644
index 0000000..a50b625
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedAuthenticatedUser.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.sharing.user;
+
+import java.util.UUID;
+import org.apache.guacamole.auth.jdbc.user.RemoteAuthenticatedUser;
+import org.apache.guacamole.net.auth.AuthenticatedUser;
+import org.apache.guacamole.net.auth.AuthenticationProvider;
+import org.apache.guacamole.net.auth.Credentials;
+
+/**
+ * Associates a user with the credentials they used to authenticate, including
+ * any provided share key.
+ *
+ * @author Michael Jumper
+ */
+public class SharedAuthenticatedUser extends RemoteAuthenticatedUser {
+
+    /**
+     * The username of this user.
+     */
+    private final String identifier;
+
+    /**
+     * The share key which was provided by this user when they authenticated. If
+     * there is no such share key, this will be null.
+     */
+    private final String shareKey;
+
+    /**
+     * Creates a new SharedAuthenticatedUser which copies the details of the
+     * given AuthenticatedUser, including that user's identifier (username).
+     * The new SharedAuthenticatedUser will not have any associated share key.
+     *
+     * @param authenticatedUser
+     *     The AuthenticatedUser to copy.
+     */
+    public SharedAuthenticatedUser(AuthenticatedUser authenticatedUser) {
+        super(authenticatedUser.getAuthenticationProvider(), authenticatedUser.getCredentials());
+        this.shareKey = null;
+        this.identifier = authenticatedUser.getIdentifier();
+    }
+
+    /**
+     * Creates a new SharedAuthenticatedUser associating the given user with
+     * their corresponding credentials and share key. The identifier (username)
+     * of the user will be randomly generated.
+     *
+     * @param authenticationProvider
+     *     The AuthenticationProvider that has authenticated the given user.
+     *
+     * @param credentials
+     *     The credentials given by the user when they authenticated.
+     *
+     * @param shareKey
+     *     The share key which was provided by this user when they
+     *     authenticated, or null if no share key was provided.
+     */
+    public SharedAuthenticatedUser(AuthenticationProvider authenticationProvider,
+            Credentials credentials, String shareKey) {
+        super(authenticationProvider, credentials);
+        this.shareKey = shareKey;
+        this.identifier = UUID.randomUUID().toString();
+    }
+
+    /**
+     * Returns the share key which was provided by this user when they
+     * authenticated. If there is no such share key, null is returned.
+     *
+     * @return
+     *     The share key which was provided by this user when they
+     *     authenticated, or null if no share key was provided.
+     */
+    public String getShareKey() {
+        return shareKey;
+    }
+
+    @Override
+    public String getIdentifier() {
+        return identifier;
+    }
+
+    @Override
+    public void setIdentifier(String identifier) {
+        throw new UnsupportedOperationException("Users authenticated via share keys are immutable.");
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/96094a1c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedUser.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedUser.java
new file mode 100644
index 0000000..2375f06
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedUser.java
@@ -0,0 +1,136 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.sharing.user;
+
+import java.util.Collections;
+import java.util.Map;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.sharing.permission.SharedObjectPermissionSet;
+import org.apache.guacamole.net.auth.AuthenticatedUser;
+import org.apache.guacamole.net.auth.Connection;
+import org.apache.guacamole.net.auth.ConnectionGroup;
+import org.apache.guacamole.net.auth.Directory;
+import org.apache.guacamole.net.auth.User;
+import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
+import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
+import org.apache.guacamole.net.auth.simple.SimpleObjectPermissionSet;
+import org.apache.guacamole.net.auth.simple.SimpleSystemPermissionSet;
+
+/**
+ * An immutable implementation of User which defines READ permission for each of
+ * the objects accessible through the various directories of a given
+ * SharedUserContext.
+ *
+ * @author Michael Jumper
+ */
+public class SharedUser implements User {
+
+    /**
+     * The AuthenticatedUser that this SharedUser represents.
+     */
+    private final AuthenticatedUser user;
+
+    /**
+     * The SharedUserContext which should be used to define which objects this
+     * SharedUser has READ permission for.
+     */
+    private final SharedUserContext userContext;
+
+    /**
+     * Creates a new SharedUser whose identity is defined by the given
+     * AuthenticatedUser, and who has strictly READ access to all objects
+     * accessible via the various directories of the given SharedUserContext.
+     *
+     * @param user
+     *     The AuthenticatedUser that the SharedUser should represent.
+     *
+     * @param userContext
+     *     The SharedUserContext which should be used to define which objects
+     *     the SharedUser has READ permission for.
+     */
+    public SharedUser(AuthenticatedUser user, SharedUserContext userContext) {
+        this.user = user;
+        this.userContext = userContext;
+    }
+
+    @Override
+    public String getIdentifier() {
+        return user.getIdentifier();
+    }
+
+    @Override
+    public void setIdentifier(String identifier) {
+        throw new UnsupportedOperationException("Users authenticated via share keys are immutable.");
+    }
+
+    @Override
+    public Map<String, String> getAttributes() {
+        return Collections.<String, String>emptyMap();
+    }
+
+    @Override
+    public void setAttributes(Map<String, String> attributes) {
+        // Do nothing - no attributes supported
+    }
+
+    @Override
+    public String getPassword() {
+        return null;
+    }
+
+    @Override
+    public void setPassword(String password) {
+        throw new UnsupportedOperationException("Users authenticated via share keys are immutable.");
+    }
+
+    @Override
+    public SystemPermissionSet getSystemPermissions() throws GuacamoleException {
+        return new SimpleSystemPermissionSet();
+    }
+
+    @Override
+    public ObjectPermissionSet getConnectionPermissions() throws GuacamoleException {
+        Directory<Connection> connectionDirectory = userContext.getConnectionDirectory();
+        return new SharedObjectPermissionSet(connectionDirectory.getIdentifiers());
+    }
+
+    @Override
+    public ObjectPermissionSet getConnectionGroupPermissions() throws GuacamoleException {
+        Directory<ConnectionGroup> connectionGroupDirectory = userContext.getConnectionGroupDirectory();
+        return new SharedObjectPermissionSet(connectionGroupDirectory.getIdentifiers());
+    }
+
+    @Override
+    public ObjectPermissionSet getUserPermissions() throws GuacamoleException {
+        Directory<User> userDirectory = userContext.getUserDirectory();
+        return new SharedObjectPermissionSet(userDirectory.getIdentifiers());
+    }
+
+    @Override
+    public ObjectPermissionSet getSharingProfilePermissions() throws GuacamoleException {
+        return new SimpleObjectPermissionSet();
+    }
+
+    @Override
+    public ObjectPermissionSet getActiveConnectionPermissions() throws GuacamoleException {
+        return new SimpleObjectPermissionSet();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/96094a1c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedUserContext.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedUserContext.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedUserContext.java
new file mode 100644
index 0000000..40f2bb5
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharing/user/SharedUserContext.java
@@ -0,0 +1,203 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.sharing.user;
+
+import com.google.inject.Inject;
+import java.util.Collection;
+import java.util.Collections;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.sharing.connection.SharedConnectionDirectory;
+import org.apache.guacamole.auth.jdbc.sharing.connectiongroup.SharedRootConnectionGroup;
+import org.apache.guacamole.auth.jdbc.user.RemoteAuthenticatedUser;
+import org.apache.guacamole.form.Form;
+import org.apache.guacamole.net.auth.ActiveConnection;
+import org.apache.guacamole.net.auth.AuthenticationProvider;
+import org.apache.guacamole.net.auth.Connection;
+import org.apache.guacamole.net.auth.ConnectionGroup;
+import org.apache.guacamole.net.auth.ConnectionRecordSet;
+import org.apache.guacamole.net.auth.Directory;
+import org.apache.guacamole.net.auth.SharingProfile;
+import org.apache.guacamole.net.auth.User;
+import org.apache.guacamole.net.auth.UserContext;
+import org.apache.guacamole.net.auth.simple.SimpleConnectionGroupDirectory;
+import org.apache.guacamole.net.auth.simple.SimpleConnectionRecordSet;
+import org.apache.guacamole.net.auth.simple.SimpleDirectory;
+import org.apache.guacamole.net.auth.simple.SimpleUserDirectory;
+
+/**
+ * The user context of a SharedUser, providing access ONLY to the user
+ * themselves, the any SharedConnections associated with that user via share
+ * keys, and an internal root connection group containing only those
+ * connections.
+ *
+ * @author Michael Jumper
+ */
+public class SharedUserContext implements UserContext {
+
+    /**
+     * The AuthenticationProvider that created this SharedUserContext.
+     */
+    private AuthenticationProvider authProvider;
+
+    /**
+     * The user whose level of access is represented by this user context.
+     */
+    private User self;
+
+    /**
+     * A directory of all connections visible to the user for whom this user
+     * context was created.
+     */
+    @Inject
+    private SharedConnectionDirectory connectionDirectory;
+
+    /**
+     * A directory of all connection groups visible to the user for whom this
+     * user context was created.
+     */
+    private Directory<ConnectionGroup> connectionGroupDirectory;
+
+    /**
+     * A directory of all users visible to the user for whom this user context
+     * was created.
+     */
+    private Directory<User> userDirectory;
+
+    /**
+     * The root connection group of the hierarchy containing all connections
+     * and connection groups visible to the user for whom this user context was
+     * created.
+     */
+    private ConnectionGroup rootGroup;
+
+    /**
+     * Creates a new SharedUserContext which provides access ONLY to the given
+     * user, the SharedConnections associated with the share keys used by that
+     * user, and an internal root connection group containing only those
+     * SharedConnections.
+     *
+     * @param authProvider
+     *     The AuthenticationProvider that created this
+     *     SharedUserContext;
+     *
+     * @param user
+     *     The RemoteAuthenticatedUser for whom this SharedUserContext is being
+     *     created.
+     */
+    public void init(AuthenticationProvider authProvider, RemoteAuthenticatedUser user) {
+
+        // Associate the originating authentication provider
+        this.authProvider = authProvider;
+
+        // Provide access to all connections shared with the given user
+        this.connectionDirectory.init(user);
+
+        // The connection group directory contains only the root group
+        this.rootGroup = new SharedRootConnectionGroup(this);
+        this.connectionGroupDirectory = new SimpleConnectionGroupDirectory(
+                Collections.singletonList(this.rootGroup));
+
+        // The user directory contains only this user
+        this.self = new SharedUser(user, this);
+        this.userDirectory = new SimpleUserDirectory(this.self);
+
+    }
+
+    /**
+     * Registers a new share key with this SharedUserContext such that the user
+     * will have access to the connection associated with that share key. The
+     * share key will be automatically de-registered when it is no longer valid.
+     *
+     * @param shareKey
+     *     The share key to register.
+     */
+    public void registerShareKey(String shareKey) {
+        connectionDirectory.registerShareKey(shareKey);
+    }
+
+    @Override
+    public User self() {
+        return self;
+    }
+
+    @Override
+    public AuthenticationProvider getAuthenticationProvider() {
+        return authProvider;
+    }
+
+    @Override
+    public Directory<User> getUserDirectory() {
+        return userDirectory;
+    }
+
+    @Override
+    public Directory<Connection> getConnectionDirectory()
+            throws GuacamoleException {
+        return connectionDirectory;
+    }
+
+    @Override
+    public Directory<ConnectionGroup> getConnectionGroupDirectory() {
+        return connectionGroupDirectory;
+    }
+
+    @Override
+    public Directory<ActiveConnection> getActiveConnectionDirectory()
+            throws GuacamoleException {
+        return new SimpleDirectory<ActiveConnection>();
+    }
+
+    @Override
+    public Directory<SharingProfile> getSharingProfileDirectory()
+            throws GuacamoleException {
+        return new SimpleDirectory<SharingProfile>();
+    }
+
+    @Override
+    public ConnectionRecordSet getConnectionHistory() {
+        return new SimpleConnectionRecordSet();
+    }
+
+    @Override
+    public ConnectionGroup getRootConnectionGroup() {
+        return rootGroup;
+    }
+
+    @Override
+    public Collection<Form> getUserAttributes() {
+        return Collections.<Form>emptyList();
+    }
+
+    @Override
+    public Collection<Form> getConnectionAttributes() {
+        return Collections.<Form>emptyList();
+    }
+
+    @Override
+    public Collection<Form> getConnectionGroupAttributes() {
+        return Collections.<Form>emptyList();
+    }
+
+    @Override
+    public Collection<Form> getSharingProfileAttributes() {
+        return Collections.<Form>emptyList();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-guacamole-client/blob/96094a1c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java
index 6ec329b..e178f7a 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java
@@ -55,8 +55,7 @@ import org.apache.guacamole.token.StandardTokens;
 import org.apache.guacamole.token.TokenFilter;
 import org.mybatis.guice.transactional.Transactional;
 import org.apache.guacamole.auth.jdbc.connection.ConnectionParameterMapper;
-import org.apache.guacamole.auth.jdbc.sharing.SharedConnectionDefinition;
-import org.apache.guacamole.auth.jdbc.sharing.SharedConnectionUser;
+import org.apache.guacamole.auth.jdbc.sharing.connection.SharedConnectionDefinition;
 import org.apache.guacamole.auth.jdbc.sharingprofile.ModeledSharingProfile;
 import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileParameterMapper;
 import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileParameterModel;
@@ -695,7 +694,7 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
 
     @Override
     @Transactional
-    public GuacamoleTunnel getGuacamoleTunnel(SharedConnectionUser user,
+    public GuacamoleTunnel getGuacamoleTunnel(RemoteAuthenticatedUser user,
             SharedConnectionDefinition definition,
             GuacamoleClientInformation info)
             throws GuacamoleException {