You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by vn...@apache.org on 2018/10/01 18:08:02 UTC

[01/38] guacamole-client git commit: GUACAMOLE-220: Refactor handling of JDBC permissions to abstract away users vs. user groups.

Repository: guacamole-client
Updated Branches:
  refs/heads/master 3ff58129c -> 658ce7884


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
index 0bb199e..9b65471 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
@@ -33,16 +33,10 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TimeZone;
-import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObject;
 import org.apache.guacamole.auth.jdbc.security.PasswordEncryptionService;
 import org.apache.guacamole.auth.jdbc.security.SaltService;
-import org.apache.guacamole.auth.jdbc.permission.SystemPermissionService;
 import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissionService;
-import org.apache.guacamole.auth.jdbc.permission.ConnectionGroupPermissionService;
-import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionService;
-import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService;
-import org.apache.guacamole.auth.jdbc.permission.UserPermissionService;
+import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
 import org.apache.guacamole.form.BooleanField;
 import org.apache.guacamole.form.DateField;
 import org.apache.guacamole.form.EmailField;
@@ -55,10 +49,6 @@ import org.apache.guacamole.net.auth.ActivityRecord;
 import org.apache.guacamole.net.auth.Permissions;
 import org.apache.guacamole.net.auth.RelatedObjectSet;
 import org.apache.guacamole.net.auth.User;
-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.net.auth.simple.SimpleObjectPermissionSet;
 import org.apache.guacamole.net.auth.simple.SimpleRelatedObjectSet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -66,7 +56,7 @@ import org.slf4j.LoggerFactory;
 /**
  * An implementation of the User object which is backed by a database model.
  */
-public class ModeledUser extends ModeledDirectoryObject<UserModel> implements User {
+public class ModeledUser extends ModeledPermissions<UserModel> implements User {
 
     /**
      * Logger for this class.
@@ -187,42 +177,6 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
     private SaltService saltService;
 
     /**
-     * Service for retrieving system permissions.
-     */
-    @Inject
-    private SystemPermissionService systemPermissionService;
-
-    /**
-     * Service for retrieving connection permissions.
-     */
-    @Inject
-    private ConnectionPermissionService connectionPermissionService;
-
-    /**
-     * Service for retrieving connection group permissions.
-     */
-    @Inject
-    private ConnectionGroupPermissionService connectionGroupPermissionService;
-
-    /**
-     * Service for retrieving sharing profile permissions.
-     */
-    @Inject
-    private SharingProfilePermissionService sharingProfilePermissionService;
-
-    /**
-     * Service for retrieving active connection permissions.
-     */
-    @Inject
-    private ActiveConnectionPermissionService activeConnectionPermissionService;
-
-    /**
-     * Service for retrieving user permissions.
-     */
-    @Inject
-    private UserPermissionService userPermissionService;
-
-    /**
      * Whether attributes which control access restrictions should be exposed
      * via getAttributes() or allowed to be set via setAttributes().
      */
@@ -332,70 +286,6 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
     }
 
     /**
-     * Returns whether this user is a system administrator, and thus is not
-     * restricted by permissions, taking into account permission inheritance
-     * via user groups.
-     *
-     * @return
-     *    true if this user is a system administrator, false otherwise.
-     *
-     * @throws GuacamoleException 
-     *    If an error occurs while determining the user's system administrator
-     *    status.
-     */
-    public boolean isAdministrator() throws GuacamoleException {
-        SystemPermissionSet systemPermissionSet = getEffectivePermissions().getSystemPermissions();
-        return systemPermissionSet.hasPermission(SystemPermission.Type.ADMINISTER);
-    }
-    
-    @Override
-    public SystemPermissionSet getSystemPermissions()
-            throws GuacamoleException {
-        return systemPermissionService.getPermissionSet(getCurrentUser(), this,
-                Collections.<String>emptySet());
-    }
-
-    @Override
-    public ObjectPermissionSet getConnectionPermissions()
-            throws GuacamoleException {
-        return connectionPermissionService.getPermissionSet(getCurrentUser(),
-                this, Collections.<String>emptySet());
-    }
-
-    @Override
-    public ObjectPermissionSet getConnectionGroupPermissions()
-            throws GuacamoleException {
-        return connectionGroupPermissionService.getPermissionSet(
-                getCurrentUser(), this, Collections.<String>emptySet());
-    }
-
-    @Override
-    public ObjectPermissionSet getSharingProfilePermissions()
-            throws GuacamoleException {
-        return sharingProfilePermissionService.getPermissionSet(
-                getCurrentUser(), this, Collections.<String>emptySet());
-    }
-
-    @Override
-    public ObjectPermissionSet getActiveConnectionPermissions()
-            throws GuacamoleException {
-        return activeConnectionPermissionService.getPermissionSet(
-                getCurrentUser(), this, Collections.<String>emptySet());
-    }
-
-    @Override
-    public ObjectPermissionSet getUserPermissions()
-            throws GuacamoleException {
-        return userPermissionService.getPermissionSet(getCurrentUser(), this,
-                Collections.<String>emptySet());
-    }
-
-    @Override
-    public ObjectPermissionSet getUserGroupPermissions() throws GuacamoleException {
-        return new SimpleObjectPermissionSet();
-    }
-
-    /**
      * Stores all restricted (privileged) attributes within the given Map,
      * pulling the values of those attributes from the underlying user model.
      * If no value is yet defined for an attribute, that attribute will be set
@@ -860,84 +750,9 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
         return new SimpleRelatedObjectSet();
     }
 
-    /**
-     * Returns the identifiers of all user groups defined within the database
-     * which apply to this user, including any groups inherited through
-     * membership in yet more groups.
-     *
-     * @return
-     *     The identifiers of all user groups defined within the database which
-     *     apply to this user.
-     */
-    public Set<String> getEffectiveUserGroups() {
-        return userService.retrieveEffectiveGroups(this,
-                Collections.<String>emptySet());
-    }
-
     @Override
     public Permissions getEffectivePermissions() throws GuacamoleException {
-
-        final ModeledAuthenticatedUser authenticatedUser = getCurrentUser();
-        final Set<String> effectiveGroups;
-
-        // If this user is the currently-authenticated user, include any
-        // additional effective groups declared by the authentication system
-        if (authenticatedUser.getIdentifier().equals(getIdentifier()))
-            effectiveGroups = userService.retrieveEffectiveGroups(this,
-                    authenticatedUser.getEffectiveUserGroups());
-
-        // Otherwise, just include effective groups from the database
-        else
-            effectiveGroups = getEffectiveUserGroups();
-
-        // Return a permissions object which describes all effective
-        // permissions, including any permissions inherited via user groups
-        return new Permissions() {
-
-            @Override
-            public ObjectPermissionSet getActiveConnectionPermissions()
-                    throws GuacamoleException {
-                return activeConnectionPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups);
-            }
-
-            @Override
-            public ObjectPermissionSet getConnectionGroupPermissions()
-                    throws GuacamoleException {
-                return connectionGroupPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups);
-            }
-
-            @Override
-            public ObjectPermissionSet getConnectionPermissions()
-                    throws GuacamoleException {
-                return connectionPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups);
-            }
-
-            @Override
-            public ObjectPermissionSet getSharingProfilePermissions()
-                    throws GuacamoleException {
-                return sharingProfilePermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups);
-            }
-
-            @Override
-            public SystemPermissionSet getSystemPermissions()
-                    throws GuacamoleException {
-                return systemPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups);
-            }
-
-            @Override
-            public ObjectPermissionSet getUserPermissions()
-                    throws GuacamoleException {
-                return userPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups);
-            }
-
-            @Override
-            public ObjectPermissionSet getUserGroupPermissions()
-                    throws GuacamoleException {
-                // FIXME: STUB
-                return new SimpleObjectPermissionSet();
-            }
-
-        };
+        return super.getEffective();
     }
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserMapper.java
index 6b51105..cf829be 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserMapper.java
@@ -19,8 +19,6 @@
 
 package org.apache.guacamole.auth.jdbc.user;
 
-import java.util.Collection;
-import java.util.Set;
 import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
 import org.apache.ibatis.annotations.Param;
 
@@ -41,24 +39,4 @@ public interface UserMapper extends ModeledDirectoryObjectMapper<UserModel> {
      */
     UserModel selectOne(@Param("username") String username);
 
-    /**
-     * Returns the set of all group identifiers of which the given user is a
-     * member, taking into account the given collection of known group
-     * memberships which are not necessarily defined within the database.
-     *
-     * @param user
-     *     The user whose effective groups should be returned.
-     *
-     * @param effectiveGroups
-     *     The identifiers of any known effective groups that should be taken
-     *     into account, such as those defined externally to the database.
-     *
-     * @return
-     *     The set of identifiers of all groups that the given user is a
-     *     member of, including those where membership is inherited through
-     *     membership in other groups.
-     */
-    Set<String> selectEffectiveGroupIdentifiers(@Param("user") UserModel user,
-            @Param("effectiveGroups") Collection<String> effectiveGroups);
-
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
index 6d89125..60bd1e1 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
@@ -26,7 +26,6 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import java.util.Set;
 import javax.servlet.http.HttpServletRequest;
 import org.apache.guacamole.net.auth.Credentials;
 import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
@@ -598,31 +597,4 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
 
     }
 
-    /**
-     * Returns the set of all group identifiers of which the given user is a
-     * member, taking into account the given collection of known group
-     * memberships which are not necessarily defined within the database.
-     * 
-     * Note that group visibility with respect to the queried user is NOT taken
-     * into account. If the user is a member of a group, the identifier of that
-     * group will be included in the returned set even if the current user lacks
-     * "READ" permission for that group.
-     *
-     * @param user
-     *     The user whose effective groups should be returned.
-     *
-     * @param effectiveGroups
-     *     The identifiers of any known effective groups that should be taken
-     *     into account, such as those defined externally to the database.
-     *
-     * @return
-     *     The set of identifiers of all groups that the given user is a
-     *     member of, including those where membership is inherited through
-     *     membership in other groups.
-     */
-    public Set<String> retrieveEffectiveGroups(ModeledUser user,
-            Collection<String> effectiveGroups) {
-        return userMapper.selectEffectiveGroupIdentifiers(user.getModel(), effectiveGroups);
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
index 01830d7..b2ae26c 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
@@ -59,6 +59,44 @@
         )
     </sql>
 
+    <!-- Select names of all effective groups (including inherited) -->
+    <select id="selectEffectiveGroupIdentifiers" resultType="string">
+
+        WITH RECURSIVE related_entity(entity_id) AS (
+                SELECT
+                    guacamole_user_group.entity_id
+                FROM guacamole_user_group
+                JOIN guacamole_user_group_member ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
+                WHERE
+                    guacamole_user_group_member.member_entity_id = #{entity.entityID}
+            <if test="!effectiveGroups.isEmpty()">
+                UNION
+                    SELECT
+                        guacamole_entity.entity_id
+                    FROM guacamole_entity
+                    WHERE
+                        type = 'USER_GROUP'::guacamole_entity_type
+                        AND name IN
+                            <foreach collection="effectiveGroups" item="effectiveGroup"
+                                     open="(" separator="," close=")">
+                                #{effectiveGroup,jdbcType=VARCHAR}
+                            </foreach>
+            </if>
+            UNION
+                SELECT
+                    guacamole_user_group.entity_id
+                FROM related_entity
+                JOIN guacamole_user_group_member ON related_entity.entity_id = guacamole_user_group_member.member_entity_id
+                JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
+        )
+        SELECT name
+        FROM related_entity
+        JOIN guacamole_entity ON related_entity.entity_id = guacamole_entity.entity_id
+        WHERE
+            guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type;
+
+    </select>
+
     <!-- Insert single entity -->
     <insert id="insert" useGeneratedKeys="true" keyProperty="entity.entityID"
             parameterType="org.apache.guacamole.auth.jdbc.base.EntityModel">

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
index 25d7659..1181b37 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
@@ -79,44 +79,6 @@
             AND permission = 'READ'
     </select>
 
-    <!-- Select names of all effective (including inherited) groups -->
-    <select id="selectEffectiveGroupIdentifiers" resultType="string">
-
-        WITH RECURSIVE related_entity(entity_id) AS (
-                SELECT
-                    guacamole_user_group.entity_id
-                FROM guacamole_user_group
-                JOIN guacamole_user_group_member ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
-                WHERE
-                    guacamole_user_group_member.member_entity_id = #{user.entityID}
-            <if test="!effectiveGroups.isEmpty()">
-                UNION
-                    SELECT
-                        guacamole_entity.entity_id
-                    FROM guacamole_entity
-                    WHERE
-                        type = 'USER_GROUP'::guacamole_entity_type
-                        AND name IN
-                            <foreach collection="effectiveGroups" item="effectiveGroup"
-                                     open="(" separator="," close=")">
-                                #{effectiveGroup,jdbcType=VARCHAR}
-                            </foreach>
-            </if>
-            UNION
-                SELECT
-                    guacamole_user_group.entity_id
-                FROM related_entity
-                JOIN guacamole_user_group_member ON related_entity.entity_id = guacamole_user_group_member.member_entity_id
-                JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
-        )
-        SELECT name
-        FROM related_entity
-        JOIN guacamole_entity ON related_entity.entity_id = guacamole_entity.entity_id
-        WHERE
-            guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type;
-
-    </select>
-
     <!-- Select multiple users by username -->
     <select id="select" resultMap="UserResultMap"
             resultSets="users,arbitraryAttributes">


[26/38] guacamole-client git commit: GUACAMOLE-220: Update SQL Server mapping with respect to user group support.

Posted by vn...@apache.org.
GUACAMOLE-220: Update SQL Server mapping with respect to user group support.


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

Branch: refs/heads/master
Commit: ee356201948c7d566b37733dcbe1fb0098d95a6d
Parents: dec7b3c
Author: Michael Jumper <mj...@apache.org>
Authored: Sat Sep 8 18:52:10 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:53 2018 -0700

----------------------------------------------------------------------
 .../guacamole/auth/jdbc/base/EntityMapper.xml   | 123 ++++++++++
 .../auth/jdbc/connection/ConnectionMapper.xml   |  30 ++-
 .../jdbc/connection/ConnectionRecordMapper.xml  |  22 +-
 .../connectiongroup/ConnectionGroupMapper.xml   |  36 ++-
 .../ConnectionGroupPermissionMapper.xml         |  52 +++--
 .../permission/ConnectionPermissionMapper.xml   |  44 ++--
 .../SharingProfilePermissionMapper.xml          |  44 ++--
 .../jdbc/permission/SystemPermissionMapper.xml  |  40 ++--
 .../permission/UserGroupPermissionMapper.xml    | 153 +++++++++++++
 .../jdbc/permission/UserPermissionMapper.xml    | 100 ++++----
 .../sharingprofile/SharingProfileMapper.xml     |  18 +-
 .../auth/jdbc/user/PasswordRecordMapper.xml     |   3 +-
 .../guacamole/auth/jdbc/user/UserMapper.xml     |  84 +++++--
 .../jdbc/user/UserParentUserGroupMapper.xml     |  96 ++++++++
 .../auth/jdbc/user/UserRecordMapper.xml         |  29 ++-
 .../auth/jdbc/usergroup/UserGroupMapper.xml     | 229 +++++++++++++++++++
 .../UserGroupMemberUserGroupMapper.xml          |  93 ++++++++
 .../usergroup/UserGroupMemberUserMapper.xml     |  93 ++++++++
 .../UserGroupParentUserGroupMapper.xml          |  96 ++++++++
 19 files changed, 1218 insertions(+), 167 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
new file mode 100644
index 0000000..f61463a
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.base.EntityMapper" >
+
+    <!--
+      * SQL fragment which tests whether the value of the given column matches
+      * the given entity ID. If group identifiers are provided, the IDs of the
+      * entities for all groups having those identifiers are tested, as well.
+      * Disabled groups are ignored.
+      *
+      * @param column
+      *     The name of the column to test. This column MUST contain an entity
+      *     ID (a foreign key into the [guacamole_entity] table).
+      *
+      * @param entityID
+      *     The ID of the specific entity to test the column against.
+      *
+      * @param groups
+      *     A collection of group identifiers to additionally test the column
+      *     against. Though this functionality is optional, a collection must
+      *     always be given, even if that collection is empty.
+      -->
+    <sql id="isRelatedEntity">
+        (
+            ${column} = ${entityID}
+            <if test="!${groups}.isEmpty()">
+                OR ${column} IN (
+                    SELECT [guacamole_entity].entity_id
+                    FROM [guacamole_entity]
+                    JOIN [guacamole_user_group] ON [guacamole_user_group].entity_id = [guacamole_entity].entity_id
+                    WHERE
+                        type = 'USER_GROUP'
+                        AND name IN
+                            <foreach collection="${groups}" item="effectiveGroup"
+                                     open="(" separator="," close=")">
+                                #{effectiveGroup,jdbcType=VARCHAR}
+                            </foreach>
+                        AND disabled = 0
+                )
+            </if>
+        )
+    </sql>
+
+    <!-- Select names of all effective groups (including inherited) -->
+    <select id="selectEffectiveGroupIdentifiers" resultType="string">
+
+        WITH [related_entity] ([entity_id]) AS (
+            SELECT
+                [guacamole_user_group].entity_id
+            FROM [guacamole_user_group]
+            JOIN [guacamole_user_group_member] ON [guacamole_user_group].user_group_id = [guacamole_user_group_member].user_group_id
+            WHERE
+                [guacamole_user_group_member].member_entity_id = #{entity.entityID}
+                AND [guacamole_user_group].disabled = 0
+            <if test="!effectiveGroups.isEmpty()">
+                UNION ALL
+                    SELECT
+                        [guacamole_entity].entity_id
+                    FROM [guacamole_entity]
+                    JOIN [guacamole_user_group] ON [guacamole_user_group].entity_id = [guacamole_entity].entity_id
+                    WHERE
+                        type = 'USER_GROUP'
+                        AND name IN
+                            <foreach collection="effectiveGroups" item="effectiveGroup"
+                                     open="(" separator="," close=")">
+                                #{effectiveGroup,jdbcType=VARCHAR}
+                            </foreach>
+                        AND [guacamole_user_group].disabled = 0
+            </if>
+            UNION ALL
+                SELECT
+                    [guacamole_user_group].entity_id
+                FROM [related_entity]
+                JOIN [guacamole_user_group_member] ON [related_entity].entity_id = [guacamole_user_group_member].member_entity_id
+                JOIN [guacamole_user_group] ON [guacamole_user_group].user_group_id = [guacamole_user_group_member].user_group_id
+                WHERE
+                    [guacamole_user_group].disabled = 0
+        )
+        SELECT DISTINCT name
+        FROM [related_entity]
+        JOIN [guacamole_entity] ON [related_entity].entity_id = [guacamole_entity].entity_id
+        WHERE
+            [guacamole_entity].type = 'USER_GROUP';
+
+    </select>
+
+    <!-- Insert single entity -->
+    <insert id="insert" useGeneratedKeys="true" keyProperty="entity.entityID"
+            parameterType="org.apache.guacamole.auth.jdbc.base.EntityModel">
+
+        INSERT INTO [guacamole_entity] (
+            name,
+            type
+        )
+        VALUES (
+            #{entity.identifier,jdbcType=VARCHAR},
+            #{entity.entityType,jdbcType=VARCHAR}
+        )
+
+    </insert>
+
+</mapper>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
index fb61757..54cb575 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
@@ -68,7 +68,11 @@
         SELECT connection_id
         FROM [guacamole_connection_permission]
         WHERE
-            user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
     </select>
 
@@ -89,7 +93,11 @@
         WHERE
             <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}</if>
             <if test="parentIdentifier == null">parent_id IS NULL</if>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
     </select>
 
@@ -170,7 +178,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}
             </foreach>
-            AND [guacamole_connection_permission].user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_connection_permission].entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
         SELECT primary_connection_id, [guacamole_sharing_profile].sharing_profile_id
@@ -181,7 +193,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
         SELECT
@@ -195,7 +211,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
index d7ae41c..2abf1ae 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
@@ -79,7 +79,10 @@
             #{record.sharingProfileIdentifier,jdbcType=INTEGER},
             #{record.sharingProfileName,jdbcType=VARCHAR},
             (SELECT user_id FROM [guacamole_user]
-             WHERE username = #{record.username,jdbcType=VARCHAR}),
+             JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
+             WHERE
+                   [guacamole_entity].name = #{record.username,jdbcType=VARCHAR}
+               AND [guacamole_entity].type = 'USER'),
             #{record.username,jdbcType=VARCHAR},
             #{record.startDate,jdbcType=TIMESTAMP},
             #{record.endDate,jdbcType=TIMESTAMP}
@@ -161,13 +164,21 @@
         <!-- Restrict to readable connections -->
         JOIN [guacamole_connection_permission] ON
                 [guacamole_connection_history].connection_id = [guacamole_connection_permission].connection_id
-            AND [guacamole_connection_permission].user_id    = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_connection_permission].entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND [guacamole_connection_permission].permission = 'READ'
 
         <!-- Restrict to readable users -->
         JOIN [guacamole_user_permission] ON
                 [guacamole_connection_history].user_id = [guacamole_user_permission].affected_user_id
-            AND [guacamole_user_permission].user_id    = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_user_permission].entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND [guacamole_user_permission].permission = 'READ'
 
         <!-- Search terms -->
@@ -178,7 +189,10 @@
                 [guacamole_connection_history].user_id IN (
                     SELECT user_id
                     FROM [guacamole_user]
-                    WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
+                    JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
+                    WHERE
+                            POSITION(#{term.term,jdbcType=VARCHAR} IN [guacamole_entity].name) > 0
+                        AND [guacamole_entity].type = 'USER'
                 )
 
                 OR [guacamole_connection_history].connection_id IN (

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
index f75943e..32c1d13 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
@@ -69,7 +69,11 @@
         SELECT connection_group_id
         FROM [guacamole_connection_group_permission]
         WHERE
-            user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
     </select>
 
@@ -90,7 +94,11 @@
         WHERE
             <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}</if>
             <if test="parentIdentifier == null">parent_id IS NULL</if>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
     </select>
 
@@ -161,7 +169,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
         SELECT parent_id, [guacamole_connection_group].connection_group_id
@@ -172,7 +184,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
         SELECT parent_id, [guacamole_connection].connection_id
@@ -183,7 +199,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
         SELECT
@@ -197,7 +217,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
index 3cc0988..b891868 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
@@ -25,24 +25,26 @@
 
     <!-- Result mapper for connection permissions -->
     <resultMap id="ConnectionGroupPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
-        <result column="user_id"             property="userID"           jdbcType="INTEGER"/>
-        <result column="username"            property="username"         jdbcType="VARCHAR"/>
+        <result column="entity_id"           property="entityID"         jdbcType="INTEGER"/>
         <result column="permission"          property="type"             jdbcType="VARCHAR"
                 javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
         <result column="connection_group_id" property="objectIdentifier" jdbcType="INTEGER"/>
     </resultMap>
 
-    <!-- Select all permissions for a given user -->
+    <!-- Select all permissions for a given entity -->
     <select id="select" resultMap="ConnectionGroupPermissionResultMap">
 
         SELECT
-            [guacamole_connection_group_permission].user_id,
-            username,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             connection_group_id
         FROM [guacamole_connection_group_permission]
-        JOIN [guacamole_user] ON [guacamole_connection_group_permission].user_id = [guacamole_user].user_id
-        WHERE [guacamole_connection_group_permission].user_id = #{user.objectID,jdbcType=INTEGER}
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
 
     </select>
 
@@ -50,26 +52,32 @@
     <select id="selectOne" resultMap="ConnectionGroupPermissionResultMap">
 
         SELECT
-            [guacamole_connection_group_permission].user_id,
-            username,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             connection_group_id
         FROM [guacamole_connection_group_permission]
-        JOIN [guacamole_user] ON [guacamole_connection_group_permission].user_id = [guacamole_user].user_id
         WHERE
-            [guacamole_connection_group_permission].user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = #{type,jdbcType=VARCHAR}
             AND connection_group_id = #{identifier,jdbcType=INTEGER}
 
     </select>
 
-    <!-- Select identifiers accessible by the given user for the given permissions -->
+    <!-- Select identifiers accessible by the given entity for the given permissions -->
     <select id="selectAccessibleIdentifiers" resultType="string">
 
         SELECT DISTINCT connection_group_id 
         FROM [guacamole_connection_group_permission]
         WHERE
-            user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND connection_group_id IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">
@@ -87,12 +95,12 @@
     <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         DELETE FROM [guacamole_connection_group_permission]
-        WHERE (user_id, permission, connection_group_id) IN
+        WHERE
             <foreach collection="permissions" item="permission"
-                     open="(" separator="," close=")">
-                (#{permission.userID,jdbcType=INTEGER},
-                 #{permission.type,jdbcType=VARCHAR},
-                 #{permission.objectIdentifier,jdbcType=INTEGER})
+                     open="(" separator=" OR " close=")">
+                (entity_id = #{permission.entityID,jdbcType=INTEGER} AND
+                 permission = #{permission.type,jdbcType=VARCHAR} AND
+                 connection_group_id = #{permission.objectIdentifier,jdbcType=INTEGER})
             </foreach>
 
     </delete>
@@ -101,24 +109,24 @@
     <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         INSERT INTO [guacamole_connection_group_permission] (
-            user_id,
+            entity_id,
             permission,
             connection_group_id
         )
         SELECT DISTINCT
-            permissions.user_id,
+            permissions.entity_id,
             permissions.permission,
             permissions.connection_group_id
         FROM
             <foreach collection="permissions" item="permission"
                      open="(" separator="UNION ALL" close=")">
-                SELECT #{permission.userID,jdbcType=INTEGER}                                 AS user_id,
+                SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id,
                        #{permission.type,jdbcType=VARCHAR} AS permission,
                        #{permission.objectIdentifier,jdbcType=INTEGER} AS connection_group_id
             </foreach>
         AS permissions
         WHERE NOT EXISTS (SELECT 1 FROM [guacamole_connection_group_permission]
-            WHERE [guacamole_connection_group_permission].user_id = permissions.user_id AND
+            WHERE [guacamole_connection_group_permission].entity_id = permissions.entity_id AND
             [guacamole_connection_group_permission].permission = permissions.permission AND
             [guacamole_connection_group_permission].connection_group_id = permissions.connection_group_id
         );

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
index aaa555a..acd02ab 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
@@ -25,24 +25,26 @@
 
     <!-- Result mapper for connection permissions -->
     <resultMap id="ConnectionPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
-        <result column="user_id"       property="userID"           jdbcType="INTEGER"/>
-        <result column="username"      property="username"         jdbcType="VARCHAR"/>
+        <result column="entity_id"     property="entityID"         jdbcType="INTEGER"/>
         <result column="permission"    property="type"             jdbcType="VARCHAR"
                 javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
         <result column="connection_id" property="objectIdentifier" jdbcType="INTEGER"/>
     </resultMap>
 
-    <!-- Select all permissions for a given user -->
+    <!-- Select all permissions for a given entity -->
     <select id="select" resultMap="ConnectionPermissionResultMap">
 
         SELECT
-            [guacamole_connection_permission].user_id,
-            username,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             connection_id
         FROM [guacamole_connection_permission]
-        JOIN [guacamole_user] ON [guacamole_connection_permission].user_id = [guacamole_user].user_id
-        WHERE [guacamole_connection_permission].user_id = #{user.objectID,jdbcType=INTEGER}
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
 
     </select>
 
@@ -50,26 +52,32 @@
     <select id="selectOne" resultMap="ConnectionPermissionResultMap">
 
         SELECT
-            [guacamole_connection_permission].user_id,
-            username,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             connection_id
         FROM [guacamole_connection_permission]
-        JOIN [guacamole_user] ON [guacamole_connection_permission].user_id = [guacamole_user].user_id
         WHERE
-            [guacamole_connection_permission].user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = #{type,jdbcType=VARCHAR}
             AND connection_id = #{identifier,jdbcType=INTEGER}
 
     </select>
 
-    <!-- Select identifiers accessible by the given user for the given permissions -->
+    <!-- Select identifiers accessible by the given entity for the given permissions -->
     <select id="selectAccessibleIdentifiers" resultType="string">
 
         SELECT DISTINCT connection_id 
         FROM [guacamole_connection_permission]
         WHERE
-            user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND connection_id IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">
@@ -90,7 +98,7 @@
         WHERE
             <foreach collection="permissions" item="permission"
                      open="(" separator=" OR " close=")">
-                (user_id = #{permission.userID,jdbcType=INTEGER} AND
+                (entity_id = #{permission.entityID,jdbcType=INTEGER} AND
                  permission = #{permission.type,jdbcType=VARCHAR} AND
                  connection_id = #{permission.objectIdentifier,jdbcType=INTEGER})
             </foreach>
@@ -101,24 +109,24 @@
     <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         INSERT INTO [guacamole_connection_permission] (
-            user_id,
+            entity_id,
             permission,
             connection_id
         )
         SELECT DISTINCT
-            permissions.user_id,
+            permissions.entity_id,
             permissions.permission,
             permissions.connection_id
         FROM
             <foreach collection="permissions" item="permission"
                      open="(" separator="UNION ALL" close=")">
-                SELECT #{permission.userID,jdbcType=INTEGER} AS user_id,
+                SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id,
                        #{permission.type,jdbcType=VARCHAR} AS permission,
                        #{permission.objectIdentifier,jdbcType=INTEGER} AS connection_id
             </foreach>
         AS permissions
         WHERE NOT EXISTS ( SELECT 1 FROM [guacamole_connection_permission]
-            WHERE [guacamole_connection_permission].user_id = permissions.user_id AND
+            WHERE [guacamole_connection_permission].entity_id = permissions.entity_id AND
             [guacamole_connection_permission].permission = permissions.permission AND
             [guacamole_connection_permission].connection_id = permissions.connection_id
         );

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
index ab40d2a..7acc290 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
@@ -25,24 +25,26 @@
 
     <!-- Result mapper for sharing profile permissions -->
     <resultMap id="SharingProfilePermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
-        <result column="user_id"            property="userID"           jdbcType="INTEGER"/>
-        <result column="username"           property="username"         jdbcType="VARCHAR"/>
+        <result column="entity_id"          property="entityID"         jdbcType="INTEGER"/>
         <result column="permission"         property="type"             jdbcType="VARCHAR"
                 javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
         <result column="sharing_profile_id" property="objectIdentifier" jdbcType="INTEGER"/>
     </resultMap>
 
-    <!-- Select all permissions for a given user -->
+    <!-- Select all permissions for a given entity -->
     <select id="select" resultMap="SharingProfilePermissionResultMap">
 
         SELECT
-            [guacamole_sharing_profile_permission].user_id,
-            username,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             sharing_profile_id
         FROM [guacamole_sharing_profile_permission]
-        JOIN [guacamole_user] ON [guacamole_sharing_profile_permission].user_id = [guacamole_user].user_id
-        WHERE [guacamole_sharing_profile_permission].user_id = #{user.objectID,jdbcType=INTEGER}
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
 
     </select>
 
@@ -50,26 +52,32 @@
     <select id="selectOne" resultMap="SharingProfilePermissionResultMap">
 
         SELECT
-            [guacamole_sharing_profile_permission].user_id,
-            username,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             sharing_profile_id
         FROM [guacamole_sharing_profile_permission]
-        JOIN [guacamole_user] ON [guacamole_sharing_profile_permission].user_id = [guacamole_user].user_id
         WHERE
-            [guacamole_sharing_profile_permission].user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = #{type,jdbcType=VARCHAR}
             AND sharing_profile_id = #{identifier,jdbcType=INTEGER}
 
     </select>
 
-    <!-- Select identifiers accessible by the given user for the given permissions -->
+    <!-- Select identifiers accessible by the given entity for the given permissions -->
     <select id="selectAccessibleIdentifiers" resultType="string">
 
         SELECT DISTINCT sharing_profile_id
         FROM [guacamole_sharing_profile_permission]
         WHERE
-            user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND sharing_profile_id IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">
@@ -90,7 +98,7 @@
         WHERE
             <foreach collection="permissions" item="permission"
                      open="(" separator=" OR " close=")">
-                (user_id = #{permission.userID,jdbcType=INTEGER} AND
+                (entity_id = #{permission.entityID,jdbcType=INTEGER} AND
                  permission = #{permission.type,jdbcType=VARCHAR} AND
                  sharing_profile_id = #{permission.objectIdentifier,jdbcType=INTEGER})
             </foreach>
@@ -101,24 +109,24 @@
     <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         INSERT INTO [guacamole_sharing_profile_permission] (
-            user_id,
+            entity_id,
             permission,
             sharing_profile_id
         )
         SELECT DISTINCT
-            permissions.user_id,
+            permissions.entity_id,
             permissions.permission,
             permissions.sharing_profile_id
         FROM
             <foreach collection="permissions" item="permission"
                      open="(" separator="UNION ALL" close=")">
-                SELECT #{permission.userID,jdbcType=INTEGER} AS user_id,
+                SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id,
                        #{permission.type,jdbcType=VARCHAR} AS permission,
                        #{permission.objectIdentifier,jdbcType=INTEGER} AS sharing_profile_id
             </foreach>
         AS permissions
         WHERE NOT EXISTS (SELECT 1 FROM [guacamole_sharing_profile_permission]
-            WHERE [guacamole_sharing_profile_permission].user_id = permissions.user_id
+            WHERE [guacamole_sharing_profile_permission].entity_id = permissions.entity_id
             AND [guacamole_sharing_profile_permission].permission = permissions.permission
             AND [guacamole_sharing_profile_permission].sharing_profile_id = permissions.sharing_profile_id
         );

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
index 663b94e..2b069fe 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
@@ -25,36 +25,40 @@
 
     <!-- Result mapper for system permissions -->
     <resultMap id="SystemPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
-        <result column="user_id"    property="userID"   jdbcType="INTEGER"/>
-        <result column="username"   property="username" jdbcType="VARCHAR"/>
+        <result column="entity_id"  property="entityID" jdbcType="INTEGER"/>
         <result column="permission" property="type"     jdbcType="VARCHAR"
                 javaType="org.apache.guacamole.net.auth.permission.SystemPermission$Type"/>
     </resultMap>
 
-    <!-- Select all permissions for a given user -->
+    <!-- Select all permissions for a given entity -->
     <select id="select" resultMap="SystemPermissionResultMap">
 
-        SELECT
-            [guacamole_system_permission].user_id,
-            username,
+        SELECT DISTINCT
+            #{entity.entityID} AS entity_id,
             permission
         FROM [guacamole_system_permission]
-        JOIN [guacamole_user] ON [guacamole_system_permission].user_id = [guacamole_user].user_id
-        WHERE [guacamole_system_permission].user_id = #{user.objectID,jdbcType=INTEGER}
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
 
     </select>
 
     <!-- Select the single permission matching the given criteria -->
     <select id="selectOne" resultMap="SystemPermissionResultMap">
 
-        SELECT
-            [guacamole_system_permission].user_id,
-            username,
+        SELECT DISTINCT
+            #{entity.entityID} AS entity_id,
             permission
         FROM [guacamole_system_permission]
-        JOIN [guacamole_user] ON [guacamole_system_permission].user_id = [guacamole_user].user_id
         WHERE
-            [guacamole_system_permission].user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = #{type,jdbcType=VARCHAR}
 
     </select>
@@ -66,7 +70,7 @@
         WHERE
             <foreach collection="permissions" item="permission"
                      open="(" separator=" OR " close=")">
-                     (user_id = #{permission.userID,jdbcType=INTEGER}
+                     (entity_id = #{permission.entityID,jdbcType=INTEGER}
                       AND permission = #{permission.type,jdbcType=VARCHAR})
             </foreach>
 
@@ -76,21 +80,21 @@
     <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
 
         INSERT INTO [guacamole_system_permission] (
-            user_id,
+            entity_id,
             permission
         )
         SELECT DISTINCT
-            permissions.user_id,
+            permissions.entity_id,
             permissions.permission
         FROM
             <foreach collection="permissions" item="permission"
                      open="(" separator="UNION ALL" close=")">
-                SELECT #{permission.userID,jdbcType=INTEGER}                                 AS user_id,
+                SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id,
                        #{permission.type,jdbcType=VARCHAR} AS permission
             </foreach>
         AS permissions
         WHERE NOT EXISTS (SELECT 1 FROM [guacamole_system_permission]
-            WHERE [guacamole_system_permission].user_id = permissions.user_id
+            WHERE [guacamole_system_permission].entity_id = permissions.entity_id
             AND [guacamole_system_permission].permission = permissions.permission
         );
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml
new file mode 100644
index 0000000..331a3a3
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml
@@ -0,0 +1,153 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionMapper" >
+
+    <!-- Result mapper for user group permissions -->
+    <resultMap id="UserGroupPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
+        <result column="entity_id"         property="entityID"         jdbcType="INTEGER"/>
+        <result column="permission"        property="type"             jdbcType="VARCHAR"
+                javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
+        <result column="affected_name"     property="objectIdentifier" jdbcType="INTEGER"/>
+    </resultMap>
+
+    <!-- Select all permissions for a given entity -->
+    <select id="select" resultMap="UserGroupPermissionResultMap">
+
+        SELECT
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
+            permission,
+            affected_entity.name AS affected_name
+        FROM [guacamole_user_group_permission]
+        JOIN [guacamole_user_group] affected_group ON [guacamole_user_group_permission].affected_user_group_id = affected_group.user_group_id
+        JOIN [guacamole_entity] affected_entity ON affected_group.entity_id = affected_entity.entity_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_user_group_permission].entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND affected_entity.type = 'USER_GROUP'
+
+    </select>
+
+    <!-- Select the single permission matching the given criteria -->
+    <select id="selectOne" resultMap="UserGroupPermissionResultMap">
+
+        SELECT
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
+            permission,
+            affected_entity.name AS affected_name
+        FROM [guacamole_user_group_permission]
+        JOIN [guacamole_user_group] affected_group ON [guacamole_user_group_permission].affected_user_group_id = affected_group.user_group_id
+        JOIN [guacamole_entity] affected_entity ON affected_group.entity_id = affected_entity.entity_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_user_group_permission].entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND permission = #{type,jdbcType=VARCHAR}
+            AND affected_entity.name = #{identifier,jdbcType=VARCHAR}
+            AND affected_entity.type = 'USER_GROUP'
+
+    </select>
+
+    <!-- Select identifiers accessible by the given entity for the given permissions -->
+    <select id="selectAccessibleIdentifiers" resultType="string">
+
+        SELECT DISTINCT affected_entity.name
+        FROM [guacamole_user_group_permission]
+        JOIN [guacamole_user_group] affected_group ON [guacamole_user_group_permission].affected_user_group_id = affected_group.user_group_id
+        JOIN [guacamole_entity] affected_entity ON affected_group.entity_id = affected_entity.entity_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_user_group_permission].entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND affected_entity.name IN
+                <foreach collection="identifiers" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+            AND permission IN
+                <foreach collection="permissions" item="permission"
+                         open="(" separator="," close=")">
+                    #{permission,jdbcType=VARCHAR}
+                </foreach>
+            AND affected_entity.type = 'USER_GROUP'
+
+    </select>
+
+    <!-- Delete all given permissions -->
+    <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
+
+        DELETE [guacamole_user_group_permission]
+        FROM [guacamole_user_group_permission]
+        JOIN [guacamole_user_group] affected_group ON [guacamole_user_group_permission].affected_user_group_id = affected_group.user_group_id
+        JOIN [guacamole_entity] affected_entity ON affected_group.entity_id = affected_entity.entity_id
+        WHERE
+            <foreach collection="permissions" item="permission"
+                     open="(" separator=" OR " close=")">
+                ([guacamole_user_group_permission].entity_id = #{permission.entityID,jdbcType=INTEGER} AND
+                 permission = #{permission.type,jdbcType=VARCHAR} AND
+                 affected_entity.name = #{permission.objectIdentifier,jdbcType=VARCHAR} AND
+                 affected_entity.type = 'USER_GROUP')
+            </foreach>
+
+    </delete>
+
+    <!-- Insert all given permissions -->
+    <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
+
+        INSERT INTO [guacamole_user_group_permission] (
+            entity_id,
+            permission,
+            affected_user_group_id
+        )
+        SELECT DISTINCT
+            permissions.entity_id,
+            permissions.permission,
+            affected_group.user_group_id
+        FROM
+            <foreach collection="permissions" item="permission"
+                     open="(" separator="UNION ALL" close=")">
+                SELECT #{permission.entityID,jdbcType=INTEGER}         AS entity_id,
+                       #{permission.type,jdbcType=VARCHAR}             AS permission,
+                       #{permission.objectIdentifier,jdbcType=VARCHAR} AS affected_name
+            </foreach>
+        AS permissions
+        JOIN [guacamole_entity] affected_entity ON
+                affected_entity.name = permissions.affected_name
+            AND affected_entity.type = 'USER_GROUP'
+        JOIN [guacamole_user_group] affected_group ON affected_group.entity_id = affected_entity.entity_id
+        WHERE NOT EXISTS (SELECT 1 FROM [guacamole_user_group_permission]
+            WHERE [guacamole_user_group_permission].entity_id = permissions.entity_id
+            AND [guacamole_user_group_permission].permission = permissions.permission
+            AND [guacamole_user_group_permission].affected_user_group_id = affected_group.user_group_id
+        );
+
+    </insert>
+
+</mapper>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
index 453777d..53ed027 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
@@ -25,25 +25,29 @@
 
     <!-- Result mapper for user permissions -->
     <resultMap id="UserPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
-        <result column="user_id"           property="userID"           jdbcType="INTEGER"/>
-        <result column="username"          property="username"         jdbcType="VARCHAR"/>
+        <result column="entity_id"         property="entityID"         jdbcType="INTEGER"/>
         <result column="permission"        property="type"             jdbcType="VARCHAR"
                 javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
-        <result column="affected_username" property="objectIdentifier" jdbcType="INTEGER"/>
+        <result column="affected_name"     property="objectIdentifier" jdbcType="INTEGER"/>
     </resultMap>
 
-    <!-- Select all permissions for a given user -->
+    <!-- Select all permissions for a given entity -->
     <select id="select" resultMap="UserPermissionResultMap">
 
         SELECT
-            [guacamole_user_permission].user_id,
-            [guacamole_user].username,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
-            affected.username AS affected_username
+            affected_entity.name AS affected_name
         FROM [guacamole_user_permission]
-        JOIN [guacamole_user] ON [guacamole_user_permission].user_id = [guacamole_user].user_id
-        JOIN [guacamole_user] affected ON [guacamole_user_permission].affected_user_id = affected.user_id
-        WHERE [guacamole_user_permission].user_id = #{user.objectID,jdbcType=INTEGER}
+        JOIN [guacamole_user] affected_user ON [guacamole_user_permission].affected_user_id = affected_user.user_id
+        JOIN [guacamole_entity] affected_entity ON affected_user.entity_id = affected_entity.entity_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_user_permission].entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND affected_entity.type = 'USER'
 
     </select>
 
@@ -51,55 +55,66 @@
     <select id="selectOne" resultMap="UserPermissionResultMap">
 
         SELECT
-            [guacamole_user_permission].user_id,
-            [guacamole_user].username,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
-            affected.username AS affected_username
+            affected_entity.name AS affected_name
         FROM [guacamole_user_permission]
-        JOIN [guacamole_user] ON [guacamole_user_permission].user_id = [guacamole_user].user_id
-        JOIN [guacamole_user] affected ON [guacamole_user_permission].affected_user_id = affected.user_id
+        JOIN [guacamole_user] affected_user ON [guacamole_user_permission].affected_user_id = affected_user.user_id
+        JOIN [guacamole_entity] affected_entity ON affected_user.entity_id = affected_entity.entity_id
         WHERE
-            [guacamole_user_permission].user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_user_permission].entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = #{type,jdbcType=VARCHAR}
-            AND affected.username = #{identifier,jdbcType=INTEGER}
+            AND affected_entity.name = #{identifier,jdbcType=VARCHAR}
+            AND affected_entity.type = 'USER'
 
     </select>
 
-    <!-- Select identifiers accessible by the given user for the given permissions -->
+    <!-- Select identifiers accessible by the given entity for the given permissions -->
     <select id="selectAccessibleIdentifiers" resultType="string">
 
-        SELECT DISTINCT username
+        SELECT DISTINCT affected_entity.name
         FROM [guacamole_user_permission]
-        JOIN [guacamole_user] ON [guacamole_user_permission].affected_user_id = [guacamole_user].user_id
+        JOIN [guacamole_user] affected_user ON [guacamole_user_permission].affected_user_id = affected_user.user_id
+        JOIN [guacamole_entity] affected_entity ON affected_user.entity_id = affected_entity.entity_id
         WHERE
-            [guacamole_user_permission].user_id = #{user.objectID,jdbcType=INTEGER}
-            AND username IN
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_user_permission].entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND affected_entity.name IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">
-                    #{identifier,jdbcType=INTEGER}
+                    #{identifier,jdbcType=VARCHAR}
                 </foreach>
             AND permission IN
                 <foreach collection="permissions" item="permission"
                          open="(" separator="," close=")">
                     #{permission,jdbcType=VARCHAR}
                 </foreach>
+            AND affected_entity.type = 'USER'
 
     </select>
 
     <!-- Delete all given permissions -->
     <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
-        DELETE FROM [guacamole_user_permission]
-        USING [guacamole_user] affected
+        DELETE [guacamole_user_permission]
+        FROM [guacamole_user_permission]
+        JOIN [guacamole_user] affected_user ON [guacamole_user_permission].affected_user_id = affected_user.user_id
+        JOIN [guacamole_entity] affected_entity ON affected_user.entity_id = affected_entity.entity_id
         WHERE
-            [guacamole_user_permission].affected_user_id = affected.user_id
-            AND ([guacamole_user_permission].user_id, permission, affected.username) IN
-                <foreach collection="permissions" item="permission"
-                         open="(" separator="," close=")">
-                    (#{permission.userID,jdbcType=INTEGER},
-                     #{permission.type,jdbcType=VARCHAR},
-                     #{permission.objectIdentifier,jdbcType=INTEGER})
-                </foreach>
+            <foreach collection="permissions" item="permission"
+                     open="(" separator=" OR " close=")">
+                ([guacamole_user_permission].entity_id = #{permission.entityID,jdbcType=INTEGER} AND
+                 permission = #{permission.type,jdbcType=VARCHAR} AND
+                 affected_entity.name = #{permission.objectIdentifier,jdbcType=VARCHAR} AND
+                 affected_entity.type = 'USER')
+            </foreach>
 
     </delete>
 
@@ -107,27 +122,30 @@
     <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         INSERT INTO [guacamole_user_permission] (
-            user_id,
+            entity_id,
             permission,
             affected_user_id
         )
         SELECT DISTINCT
-            permissions.user_id,
+            permissions.entity_id,
             permissions.permission,
-            [guacamole_user].user_id
+            affected_user.user_id
         FROM
             <foreach collection="permissions" item="permission"
                      open="(" separator="UNION ALL" close=")">
-                SELECT #{permission.userID,jdbcType=INTEGER}                                 AS user_id,
+                SELECT #{permission.entityID,jdbcType=INTEGER} AS entity_id,
                        #{permission.type,jdbcType=VARCHAR} AS permission,
-                       #{permission.objectIdentifier,jdbcType=INTEGER}                       AS username
+                       #{permission.objectIdentifier,jdbcType=INTEGER} AS affected_name
             </foreach>
         AS permissions
-        JOIN [guacamole_user] ON [guacamole_user].username = permissions.username
+        JOIN [guacamole_entity] affected_entity ON
+                affected_entity.name = permissions.affected_name
+            AND affected_entity.type = 'USER'
+        JOIN [guacamole_user] affected_user ON affected_user.entity_id = affected_entity.entity_id
         WHERE NOT EXISTS (SELECT 1 FROM [guacamole_user_permission]
-            WHERE [guacamole_user_permission].user_id = permissions.user_id
+            WHERE [guacamole_user_permission].entity_id = permissions.entity_id
             AND [guacamole_user_permission].permission = permissions.permission
-            AND [guacamole_user_permission].affected_user_id = [guacamole_user].user_id
+            AND [guacamole_user_permission].affected_user_id = affected_user.user_id
         );
 
     </insert>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
index 0b3212f..dc87f53 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
@@ -52,7 +52,11 @@
         SELECT sharing_profile_id
         FROM [guacamole_sharing_profile_permission]
         WHERE
-            user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
     </select>
 
@@ -99,7 +103,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
         SELECT
@@ -113,7 +121,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml
index 20d2cfb..21fd986 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml
@@ -41,8 +41,9 @@
             [guacamole_user_password_history].password_date
         FROM [guacamole_user_password_history]
         JOIN [guacamole_user] ON [guacamole_user_password_history].user_id = [guacamole_user].user_id
+        JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
         WHERE
-            [guacamole_user].username = #{username,jdbcType=VARCHAR}
+            [guacamole_entity].name = #{username,jdbcType=VARCHAR}
         ORDER BY
             [guacamole_user_password_history].password_date DESC
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
index 177ab93..7d70950 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
@@ -28,7 +28,8 @@
 
         <!-- User properties -->
         <id     column="user_id"             property="objectID"           jdbcType="INTEGER"/>
-        <result column="username"            property="identifier"         jdbcType="VARCHAR"/>
+        <result column="entity_id"           property="entityID"           jdbcType="INTEGER"/>
+        <result column="name"                property="identifier"         jdbcType="VARCHAR"/>
         <result column="password_hash"       property="passwordHash"       jdbcType="BINARY"/>
         <result column="password_salt"       property="passwordSalt"       jdbcType="BINARY"/>
         <result column="password_date"       property="passwordDate"       jdbcType="TIMESTAMP"/>
@@ -57,17 +58,24 @@
 
     <!-- Select all usernames -->
     <select id="selectIdentifiers" resultType="string">
-        SELECT username
-        FROM [guacamole_user]
+        SELECT name
+        FROM [guacamole_entity]
+        WHERE [guacamole_entity].type = 'USER'
     </select>
 
     <!-- Select usernames of all readable users -->
     <select id="selectReadableIdentifiers" resultType="string">
-        SELECT username
+        SELECT [guacamole_entity].name
         FROM [guacamole_user]
+        JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
         JOIN [guacamole_user_permission] ON affected_user_id = [guacamole_user].user_id
         WHERE
-            [guacamole_user_permission].user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_user_permission].entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND [guacamole_entity].type = 'USER'
             AND permission = 'READ'
     </select>
 
@@ -77,7 +85,8 @@
 
         SELECT
             [guacamole_user].user_id,
-            [guacamole_user].username,
+            [guacamole_entity].entity_id,
+            [guacamole_entity].name,
             password_hash,
             password_salt,
             password_date,
@@ -98,11 +107,13 @@
                 WHERE [guacamole_user_history].user_id = [guacamole_user].user_id
             ) AS last_active
         FROM [guacamole_user]
-        WHERE [guacamole_user].username IN
+        JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
+        WHERE [guacamole_entity].name IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
-            </foreach>;
+            </foreach>
+            AND [guacamole_entity].type = 'USER';
 
         SELECT
             [guacamole_user_attribute].user_id,
@@ -110,11 +121,13 @@
             [guacamole_user_attribute].attribute_value
         FROM [guacamole_user_attribute]
         JOIN [guacamole_user] ON [guacamole_user].user_id = [guacamole_user_attribute].user_id
-        WHERE username IN
+        JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
+        WHERE [guacamole_entity].name IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
-                #{identifier,jdbcType=INTEGER}
-            </foreach>;
+                #{identifier,jdbcType=VARCHAR}
+            </foreach>
+            AND [guacamole_entity].type = 'USER';
 
     </select>
 
@@ -124,7 +137,8 @@
 
         SELECT
             [guacamole_user].user_id,
-            [guacamole_user].username,
+            [guacamole_entity].entity_id,
+            [guacamole_entity].name,
             password_hash,
             password_salt,
             password_date,
@@ -145,13 +159,19 @@
                 WHERE [guacamole_user_history].user_id = [guacamole_user].user_id
             ) AS last_active
         FROM [guacamole_user]
+        JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
         JOIN [guacamole_user_permission] ON affected_user_id = [guacamole_user].user_id
-        WHERE [guacamole_user].username IN
+        WHERE [guacamole_entity].name IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
-            AND [guacamole_user_permission].user_id = #{user.objectID,jdbcType=INTEGER}
+            AND [guacamole_entity].type = 'USER'
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_user_permission].entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
         SELECT
@@ -160,13 +180,19 @@
             [guacamole_user_attribute].attribute_value
         FROM [guacamole_user_attribute]
         JOIN [guacamole_user] ON [guacamole_user].user_id = [guacamole_user_attribute].user_id
+        JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
         JOIN [guacamole_user_permission] ON affected_user_id = [guacamole_user].user_id
-        WHERE username IN
+        WHERE [guacamole_entity].name IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
-                #{identifier,jdbcType=INTEGER}
+                #{identifier,jdbcType=VARCHAR}
             </foreach>
-            AND [guacamole_user_permission].user_id = #{user.objectID,jdbcType=INTEGER}
+            AND [guacamole_entity].type = 'USER'
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_user_permission].entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
     </select>
@@ -176,8 +202,9 @@
             resultSets="users,arbitraryAttributes">
 
         SELECT
-            user_id,
-            username,
+            [guacamole_user].user_id,
+            [guacamole_entity].entity_id,
+            [guacamole_entity].name,
             password_hash,
             password_salt,
             password_date,
@@ -198,8 +225,10 @@
                 WHERE [guacamole_user_history].user_id = [guacamole_user].user_id
             ) AS last_active
         FROM [guacamole_user]
+        JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
         WHERE
-            [guacamole_user].username = #{username,jdbcType=VARCHAR};
+            [guacamole_entity].name = #{username,jdbcType=VARCHAR}
+            AND [guacamole_entity].type = 'USER';
 
         SELECT
             [guacamole_user_attribute].user_id,
@@ -207,14 +236,19 @@
             [guacamole_user_attribute].attribute_value
         FROM [guacamole_user_attribute]
         JOIN [guacamole_user] ON [guacamole_user].user_id = [guacamole_user_attribute].user_id
-        WHERE username = #{username,jdbcType=VARCHAR};
+        JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
+        WHERE
+            [guacamole_entity].name = #{username,jdbcType=VARCHAR}
+            AND [guacamole_entity].type = 'USER'
 
     </select>
 
     <!-- Delete single user by username -->
     <delete id="delete">
-        DELETE FROM [guacamole_user]
-        WHERE username = #{identifier,jdbcType=VARCHAR}
+        DELETE FROM [guacamole_entity]
+        WHERE
+            name = #{identifier,jdbcType=VARCHAR}
+            AND type = 'USER'
     </delete>
 
     <!-- Insert single user -->
@@ -222,7 +256,7 @@
             parameterType="org.apache.guacamole.auth.jdbc.user.UserModel">
 
         INSERT INTO [guacamole_user] (
-            username,
+            entity_id,
             password_hash,
             password_salt,
             password_date,
@@ -239,7 +273,7 @@
             organizational_role
         )
         VALUES (
-            #{object.identifier,jdbcType=VARCHAR},
+            #{object.entityID,jdbcType=VARCHAR},
             #{object.passwordHash,jdbcType=BINARY},
             #{object.passwordSalt,jdbcType=BINARY},
             #{object.passwordDate,jdbcType=TIMESTAMP},

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml
new file mode 100644
index 0000000..e6eccba
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.user.UserParentUserGroupMapper" >
+
+    <!-- Select the names of all parent user groups -->
+    <select id="selectChildIdentifiers" resultType="string">
+        SELECT name
+        FROM [guacamole_user_group_member]
+        JOIN [guacamole_user_group] ON [guacamole_user_group_member].user_group_id = [guacamole_user_group].user_group_id
+        JOIN [guacamole_entity] ON [guacamole_entity].entity_id = [guacamole_user_group].entity_id
+        WHERE
+            [guacamole_user_group_member].member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            AND [guacamole_entity].type = 'USER_GROUP'
+    </select>
+
+    <!-- Select the names of all readable parent user groups -->
+    <select id="selectReadableChildIdentifiers" resultType="string">
+        SELECT [guacamole_entity].name
+        FROM [guacamole_user_group_member]
+        JOIN [guacamole_user_group] ON [guacamole_user_group_member].user_group_id = [guacamole_user_group].user_group_id
+        JOIN [guacamole_entity] ON [guacamole_entity].entity_id = [guacamole_user_group].entity_id
+        JOIN [guacamole_user_group_permission] ON affected_user_group_id = [guacamole_user_group].user_group_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_user_group_permission].entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND [guacamole_user_group_member].member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            AND [guacamole_entity].type = 'USER_GROUP'
+            AND permission = 'READ'
+    </select>
+
+    <!-- Delete parent groups by name -->
+    <delete id="delete">
+        DELETE [guacamole_user_group_member]
+        FROM [guacamole_user_group_member]
+        JOIN [guacamole_user_group] ON [guacamole_user_group].user_group_id = [guacamole_user_group_member].user_group_id
+        JOIN [guacamole_entity] ON [guacamole_entity].entity_id = [guacamole_user_group].entity_id
+        WHERE
+            member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            AND [guacamole_entity].type = 'USER_GROUP'
+            AND [guacamole_entity].name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+    </delete>
+
+    <!-- Insert parent groups by name -->
+    <insert id="insert">
+        INSERT INTO [guacamole_user_group_member] (
+            user_group_id,
+            member_entity_id
+        )
+        SELECT DISTINCT
+            [guacamole_user_group].user_group_id,
+            #{parent.entityID,jdbcType=INTEGER}
+        FROM [guacamole_user_group]
+        JOIN [guacamole_entity] ON [guacamole_user_group].entity_id = [guacamole_entity].entity_id
+        WHERE
+            [guacamole_entity].name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+            AND [guacamole_entity].type = 'USER_GROUP'
+            AND [guacamole_user_group].user_group_id NOT IN (
+                SELECT [guacamole_user_group_member].user_group_id
+                FROM [guacamole_user_group_member]
+                WHERE [guacamole_user_group_member].member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            )
+    </insert>
+
+</mapper>


[05/38] guacamole-client git commit: GUACAMOLE-220: Implement permission inheritance within SQL queries.

Posted by vn...@apache.org.
GUACAMOLE-220: Implement permission inheritance within SQL queries.


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

Branch: refs/heads/master
Commit: a1553979478bfcbd53ff28558c8e7bf2947afa46
Parents: 199f518
Author: Michael Jumper <mj...@apache.org>
Authored: Wed Apr 4 21:07:49 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:51 2018 -0700

----------------------------------------------------------------------
 .../modules/guacamole-auth-jdbc-base/pom.xml    | 10 ++---
 .../guacamole/auth/jdbc/base/EntityMapper.xml   | 17 ++++++++
 .../auth/jdbc/connection/ConnectionMapper.xml   | 35 +++++++++++++---
 .../jdbc/connection/ConnectionRecordMapper.xml  | 14 ++++++-
 .../connectiongroup/ConnectionGroupMapper.xml   | 42 +++++++++++++++++---
 .../ConnectionGroupPermissionMapper.xml         | 26 +++++++++---
 .../permission/ConnectionPermissionMapper.xml   | 26 +++++++++---
 .../SharingProfilePermissionMapper.xml          | 27 ++++++++++---
 .../jdbc/permission/SystemPermissionMapper.xml  | 23 ++++++++---
 .../jdbc/permission/UserPermissionMapper.xml    | 25 +++++++++---
 .../sharingprofile/SharingProfileMapper.xml     | 21 ++++++++--
 .../guacamole/auth/jdbc/user/UserMapper.xml     | 21 ++++++++--
 .../auth/jdbc/user/UserRecordMapper.xml         |  7 +++-
 13 files changed, 243 insertions(+), 51 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a1553979/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml
index d99534c..ab56499 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml
@@ -109,33 +109,33 @@
         <dependency>
             <groupId>org.mybatis</groupId>
             <artifactId>mybatis</artifactId>
-            <version>3.2.8</version>
+            <version>3.4.6</version>
         </dependency>
         
         <!-- MyBatis Guice -->
         <dependency>
             <groupId>org.mybatis</groupId>
             <artifactId>mybatis-guice</artifactId>
-            <version>3.6</version>
+            <version>3.10</version>
         </dependency>
 
         <!-- Guice -->
         <dependency>
             <groupId>com.google.inject</groupId>
             <artifactId>guice</artifactId>
-            <version>3.0</version>
+            <version>4.1.0</version>
         </dependency>
         <dependency>
             <groupId>com.google.inject.extensions</groupId>
             <artifactId>guice-multibindings</artifactId>
-            <version>3.0</version>
+            <version>4.1.0</version>
         </dependency>
 
         <!-- Guava - Utility Library -->
         <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
-            <version>18.0</version>
+            <version>19.0</version>
         </dependency>
 
     </dependencies>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a1553979/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
index f05c287..dd262d1 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
@@ -23,6 +23,23 @@
 
 <mapper namespace="org.apache.guacamole.auth.jdbc.base.EntityMapper" >
 
+    <!-- Retrieves the ID of the given entity. If inheritance is enabled, the
+    IDs of the entities for all applicable user groups are retrieved, as well. -->
+    <sql id="relatedEntities">
+        <if test="!${inheritFlag}">${entityID}</if>
+        <if test="${inheritFlag}">
+            WITH RECURSIVE related_entity(entity_id) AS (
+                    VALUES (${entityID})
+                UNION
+                    SELECT guacamole_user_group.entity_id
+                    FROM related_entity
+                    JOIN guacamole_user_group_member ON related_entity.entity_id = guacamole_user_group_member.member_entity_id
+                    JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
+            )
+            SELECT entity_id FROM related_entity
+        </if>
+    </sql>
+
     <!-- Insert single entity -->
     <insert id="insert" useGeneratedKeys="true" keyProperty="entity.entityID"
             parameterType="org.apache.guacamole.auth.jdbc.base.EntityModel">

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a1553979/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
index c238c78..94855e1 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
@@ -68,7 +68,12 @@
         SELECT connection_id
         FROM guacamole_connection_permission
         WHERE
-            entity_id = #{user.entityID,jdbcType=INTEGER}
+            entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = 'READ'
     </select>
 
@@ -89,7 +94,12 @@
         WHERE
             <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer</if>
             <if test="parentIdentifier == null">parent_id IS NULL</if>
-            AND entity_id = #{user.entityID,jdbcType=INTEGER}
+            AND entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = 'READ'
     </select>
 
@@ -165,7 +175,12 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND guacamole_connection_permission.entity_id = #{user.entityID,jdbcType=INTEGER}
+            AND guacamole_connection_permission.entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = 'READ'
         GROUP BY guacamole_connection.connection_id;
 
@@ -177,7 +192,12 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND entity_id = #{user.entityID,jdbcType=INTEGER}
+            AND entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = 'READ';
 
         SELECT
@@ -191,7 +211,12 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND entity_id = #{user.entityID,jdbcType=INTEGER}
+            AND entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = 'READ';
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a1553979/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
index b4407bd..b04c9ca 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
@@ -166,13 +166,23 @@
         <!-- Restrict to readable connections -->
         JOIN guacamole_connection_permission ON
                 guacamole_connection_history.connection_id = guacamole_connection_permission.connection_id
-            AND guacamole_connection_permission.user_id    = #{user.objectID,jdbcType=INTEGER}
+            AND guacamole_connection_permission.entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND guacamole_connection_permission.permission = 'READ'
 
         <!-- Restrict to readable users -->
         JOIN guacamole_user_permission ON
                 guacamole_connection_history.user_id = guacamole_user_permission.affected_user_id
-            AND guacamole_user_permission.user_id    = #{user.objectID,jdbcType=INTEGER}
+            AND guacamole_user_permission.entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND guacamole_user_permission.permission = 'READ'
 
         <!-- Search terms -->

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a1553979/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
index 7e0b188..ffca72d 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
@@ -69,7 +69,12 @@
         SELECT connection_group_id
         FROM guacamole_connection_group_permission
         WHERE
-            entity_id = #{user.entityID,jdbcType=INTEGER}
+            entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = 'READ'
     </select>
 
@@ -90,7 +95,12 @@
         WHERE
             <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer</if>
             <if test="parentIdentifier == null">parent_id IS NULL</if>
-            AND entity_id = #{user.entityID,jdbcType=INTEGER}
+            AND entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = 'READ'
     </select>
 
@@ -161,7 +171,12 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND entity_id = #{user.entityID,jdbcType=INTEGER}
+            AND entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = 'READ';
 
         SELECT parent_id, guacamole_connection_group.connection_group_id
@@ -172,7 +187,12 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND entity_id = #{user.entityID,jdbcType=INTEGER}
+            AND entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = 'READ';
 
         SELECT parent_id, guacamole_connection.connection_id
@@ -183,7 +203,12 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND entity_id = #{user.entityID,jdbcType=INTEGER}
+            AND entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = 'READ';
 
         SELECT
@@ -197,7 +222,12 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND entity_id = #{user.entityID,jdbcType=INTEGER}
+            AND entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = 'READ';
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a1553979/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
index c8ec936..a21b7d5 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
@@ -35,11 +35,17 @@
     <select id="select" resultMap="ConnectionGroupPermissionResultMap">
 
         SELECT
-            entity_id,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             connection_group_id
         FROM guacamole_connection_group_permission
-        WHERE entity_id = #{entity.entityID,jdbcType=INTEGER}
+        WHERE
+            entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="inherit"/>
+                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
 
     </select>
 
@@ -47,12 +53,17 @@
     <select id="selectOne" resultMap="ConnectionGroupPermissionResultMap">
 
         SELECT
-            entity_id,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             connection_group_id
         FROM guacamole_connection_group_permission
         WHERE
-            entity_id = #{entity.entityID,jdbcType=INTEGER}
+            entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="inherit"/>
+                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
             AND connection_group_id = #{identifier,jdbcType=INTEGER}::integer
 
@@ -64,7 +75,12 @@
         SELECT DISTINCT connection_group_id 
         FROM guacamole_connection_group_permission
         WHERE
-            entity_id = #{entity.entityID,jdbcType=INTEGER}
+            entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="inherit"/>
+                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND connection_group_id IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a1553979/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
index 99eed28..5d911de 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
@@ -35,11 +35,17 @@
     <select id="select" resultMap="ConnectionPermissionResultMap">
 
         SELECT
-            entity_id,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             connection_id
         FROM guacamole_connection_permission
-        WHERE entity_id = #{entity.entityID,jdbcType=INTEGER}
+        WHERE
+            entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="inherit"/>
+                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
 
     </select>
 
@@ -47,12 +53,17 @@
     <select id="selectOne" resultMap="ConnectionPermissionResultMap">
 
         SELECT
-            entity_id,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             connection_id
         FROM guacamole_connection_permission
         WHERE
-            entity_id = #{entity.entityID,jdbcType=INTEGER}
+            entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="inherit"/>
+                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
             AND connection_id = #{identifier,jdbcType=INTEGER}::integer
 
@@ -64,7 +75,12 @@
         SELECT DISTINCT connection_id 
         FROM guacamole_connection_permission
         WHERE
-            entity_id = #{entity.entityID,jdbcType=INTEGER}
+            entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="inherit"/>
+                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND connection_id IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a1553979/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
index 73d0ad4..68b3032 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
@@ -35,11 +35,18 @@
     <select id="select" resultMap="SharingProfilePermissionResultMap">
 
         SELECT
-            entity_id,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             sharing_profile_id
         FROM guacamole_sharing_profile_permission
-        WHERE entity_id = #{entity.entityID,jdbcType=INTEGER}
+        WHERE
+            entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="inherit"/>
+                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
+
 
     </select>
 
@@ -47,12 +54,17 @@
     <select id="selectOne" resultMap="SharingProfilePermissionResultMap">
 
         SELECT
-            entity_id,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             sharing_profile_id
         FROM guacamole_sharing_profile_permission
         WHERE
-            entity_id = #{entity.entityID,jdbcType=INTEGER}
+            entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="inherit"/>
+                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
             AND sharing_profile_id = #{identifier,jdbcType=INTEGER}::integer
 
@@ -64,7 +76,12 @@
         SELECT DISTINCT sharing_profile_id
         FROM guacamole_sharing_profile_permission
         WHERE
-            entity_id = #{entity.entityID,jdbcType=INTEGER}
+            entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="inherit"/>
+                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND sharing_profile_id IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a1553979/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
index 5e75891..25ebf97 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
@@ -33,23 +33,34 @@
     <!-- Select all permissions for a given entity -->
     <select id="select" resultMap="SystemPermissionResultMap">
 
-        SELECT
-            entity_id,
+        SELECT DISTINCT
+            #{entity.entityID} AS entity_id,
             permission
         FROM guacamole_system_permission
-        WHERE entity_id = #{entity.entityID,jdbcType=INTEGER}
+        WHERE
+            entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="inherit"/>
+                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
 
     </select>
 
     <!-- Select the single permission matching the given criteria -->
     <select id="selectOne" resultMap="SystemPermissionResultMap">
 
-        SELECT
-            entity_id,
+        SELECT DISTINCT
+            #{entity.entityID} AS entity_id,
             permission
         FROM guacamole_system_permission
         WHERE
-            entity_id = #{entity.entityID,jdbcType=INTEGER}
+            entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="inherit"/>
+                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = #{type,jdbcType=VARCHAR}::guacamole_system_permission_type
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a1553979/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
index d6680ea..e5a844a 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
@@ -35,14 +35,19 @@
     <select id="select" resultMap="UserPermissionResultMap">
 
         SELECT
-            guacamole_user_permission.entity_id,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             affected_entity.name AS affected_name
         FROM guacamole_user_permission
         JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
         JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
         WHERE
-            guacamole_user_permission.entity_id = #{entity.entityID,jdbcType=INTEGER}
+            guacamole_user_permission.entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="inherit"/>
+                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND affected_entity.type = 'USER'::guacamole_entity_type
 
     </select>
@@ -51,14 +56,19 @@
     <select id="selectOne" resultMap="UserPermissionResultMap">
 
         SELECT
-            guacamole_user_permission.entity_id,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             affected_entity.name AS affected_name
         FROM guacamole_user_permission
         JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
         JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
         WHERE
-            guacamole_user_permission.entity_id = #{entity.entityID,jdbcType=INTEGER}
+            guacamole_user_permission.entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="inherit"/>
+                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
             AND affected_entity.name = #{identifier,jdbcType=VARCHAR}
             AND affected_entity.type = 'USER'::guacamole_entity_type
@@ -73,7 +83,12 @@
         JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
         JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
         WHERE
-            guacamole_user_permission.entity_id = #{entity.entityID,jdbcType=INTEGER}
+            guacamole_user_permission.entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="inherit"/>
+                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND affected_entity.name IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a1553979/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
index 66bd701..febf540 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
@@ -52,7 +52,12 @@
         SELECT sharing_profile_id
         FROM guacamole_sharing_profile_permission
         WHERE
-            entity_id = #{user.entityID,jdbcType=INTEGER}
+            entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = 'READ'
     </select>
 
@@ -99,7 +104,12 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND entity_id = #{user.entityID,jdbcType=INTEGER}
+            AND entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = 'READ';
 
         SELECT
@@ -113,7 +123,12 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND entity_id = #{user.entityID,jdbcType=INTEGER}
+            AND entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = 'READ';
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a1553979/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
index 796962d..654351f 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
@@ -70,7 +70,12 @@
         JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
         JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
         WHERE
-            guacamole_user_permission.entity_id = #{user.entityID,jdbcType=INTEGER}
+            guacamole_user_permission.entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND guacamole_entity.type = 'USER'::guacamole_entity_type
             AND permission = 'READ'
     </select>
@@ -158,7 +163,12 @@
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
             AND guacamole_entity.type = 'USER'::guacamole_entity_type
-            AND guacamole_user_permission.entity_id = #{user.entityID,jdbcType=INTEGER}
+            AND guacamole_user_permission.entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = 'READ'
         GROUP BY guacamole_user.user_id, guacamole_entity.entity_id;
 
@@ -176,7 +186,12 @@
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
             AND guacamole_entity.type = 'USER'::guacamole_entity_type
-            AND guacamole_user_permission.entity_id = #{user.entityID,jdbcType=INTEGER}
+            AND guacamole_user_permission.entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND permission = 'READ';
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a1553979/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
index 20cb2a8..862e2d7 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
@@ -156,7 +156,12 @@
         <!-- Restrict to readable users -->
         JOIN guacamole_user_permission ON
                 guacamole_user_history.user_id       = guacamole_user_permission.affected_user_id
-            AND guacamole_user_permission.user_id    = #{user.objectID,jdbcType=INTEGER}
+            AND guacamole_user_permission.entity_id IN (
+                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
+                    <property name="inheritFlag" value="true"/>
+                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
+                </include>
+            )
             AND guacamole_user_permission.permission = 'READ'
 
         <!-- Search terms -->


[09/38] guacamole-client git commit: GUACAMOLE-220: Move JDBC handling of effective groups to RemoteAuthenticatedUser level. Stub out retrieval of effective groups.

Posted by vn...@apache.org.
GUACAMOLE-220: Move JDBC handling of effective groups to RemoteAuthenticatedUser level. Stub out retrieval of effective groups.


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

Branch: refs/heads/master
Commit: 6e71f330b8f8108751fa2fee2b5adea1ae6aecae
Parents: a155397
Author: Michael Jumper <mj...@apache.org>
Authored: Fri Apr 6 13:46:36 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:51 2018 -0700

----------------------------------------------------------------------
 .../sharing/user/SharedAuthenticatedUser.java   | 11 +++--------
 .../jdbc/user/ModeledAuthenticatedUser.java     |  9 ++-------
 .../guacamole/auth/jdbc/user/ModeledUser.java   | 16 ++++++++++++++++
 .../auth/jdbc/user/RemoteAuthenticatedUser.java | 20 +++++++++++++++++++-
 4 files changed, 40 insertions(+), 16 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/6e71f330/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
index 958213c..96c6a9e 100644
--- 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
@@ -20,7 +20,6 @@
 package org.apache.guacamole.auth.jdbc.sharing.user;
 
 import java.util.Collections;
-import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.RemoteAuthenticatedUser;
 import org.apache.guacamole.net.auth.AuthenticatedUser;
 import org.apache.guacamole.net.auth.AuthenticationProvider;
@@ -52,7 +51,8 @@ public class SharedAuthenticatedUser extends RemoteAuthenticatedUser {
      *     The AuthenticatedUser to copy.
      */
     public SharedAuthenticatedUser(AuthenticatedUser authenticatedUser) {
-        super(authenticatedUser.getAuthenticationProvider(), authenticatedUser.getCredentials());
+        super(authenticatedUser.getAuthenticationProvider(),
+                authenticatedUser.getCredentials(), Collections.<String>emptySet());
         this.shareKey = null;
         this.identifier = authenticatedUser.getIdentifier();
     }
@@ -75,7 +75,7 @@ public class SharedAuthenticatedUser extends RemoteAuthenticatedUser {
      */
     public SharedAuthenticatedUser(AuthenticationProvider authenticationProvider,
             Credentials credentials, String shareKey) {
-        super(authenticationProvider, credentials);
+        super(authenticationProvider, credentials, Collections.<String>emptySet());
         this.shareKey = shareKey;
         this.identifier = AuthenticatedUser.ANONYMOUS_IDENTIFIER;
     }
@@ -102,9 +102,4 @@ public class SharedAuthenticatedUser extends RemoteAuthenticatedUser {
         throw new UnsupportedOperationException("Users authenticated via share keys are immutable.");
     }
 
-    @Override
-    public Set<String> getEffectiveUserGroups() {
-        return Collections.<String>emptySet();
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/6e71f330/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java
index 8c201d0..e756374 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java
@@ -76,7 +76,7 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser {
      */
     public ModeledAuthenticatedUser(AuthenticatedUser authenticatedUser,
             AuthenticationProvider modelAuthenticationProvider, ModeledUser user) {
-        super(authenticatedUser.getAuthenticationProvider(), authenticatedUser.getCredentials());
+        super(authenticatedUser.getAuthenticationProvider(), authenticatedUser.getCredentials(), authenticatedUser.getEffectiveUserGroups());
         this.modelAuthenticationProvider = modelAuthenticationProvider;
         this.user = user;
     }
@@ -98,7 +98,7 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser {
      */
     public ModeledAuthenticatedUser(AuthenticationProvider authenticationProvider,
             ModeledUser user, Credentials credentials) {
-        super(authenticationProvider, credentials);
+        super(authenticationProvider, credentials, user.getEffectiveUserGroups());
         this.modelAuthenticationProvider = authenticationProvider;
         this.user = user;
     }
@@ -169,9 +169,4 @@ public class ModeledAuthenticatedUser extends RemoteAuthenticatedUser {
         user.setIdentifier(identifier);
     }
 
-    @Override
-    public Set<String> getEffectiveUserGroups() {
-        return Collections.<String>emptySet();
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/6e71f330/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
index 737aec8..0628d74 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
@@ -854,6 +854,22 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
         return new SimpleRelatedObjectSet();
     }
 
+    /**
+     * Returns the identifiers of all user groups defined within the database
+     * which apply to this user, including any groups inherited through
+     * membership in yet more groups.
+     *
+     * @return
+     *     The identifiers of all user groups defined within the database which
+     *     apply to this user.
+     */
+    public Set<String> getEffectiveUserGroups() {
+
+        // FIXME: STUB
+        return /*retrieveEffectiveIdentifiers(this, */Collections.<String>emptySet()/*)*/;
+
+    }
+
     @Override
     public Permissions getEffectivePermissions() throws GuacamoleException {
         return new Permissions() {

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/6e71f330/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java
index d68d9a9..324892e 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java
@@ -19,6 +19,8 @@
 
 package org.apache.guacamole.auth.jdbc.user;
 
+import java.util.Collections;
+import java.util.Set;
 import org.apache.guacamole.net.auth.AuthenticatedUser;
 import org.apache.guacamole.net.auth.AuthenticationProvider;
 import org.apache.guacamole.net.auth.Credentials;
@@ -44,6 +46,12 @@ public abstract class RemoteAuthenticatedUser implements AuthenticatedUser {
     private final String remoteHost;
 
     /**
+     * The identifiers of any groups of which this user is a member, including
+     * groups inherited through membership in other groups.
+     */
+    private final Set<String> effectiveGroups;
+
+    /**
      * Creates a new RemoteAuthenticatedUser, deriving the associated remote
      * host from the given credentials.
      *
@@ -52,12 +60,17 @@ public abstract class RemoteAuthenticatedUser implements AuthenticatedUser {
      *
      * @param credentials 
      *     The credentials given by the user when they authenticated.
+     *
+     * @param effectiveGroups
+     *     The identifiers of any groups of which this user is a member,
+     *     including groups inherited through membership in other groups.
      */
     public RemoteAuthenticatedUser(AuthenticationProvider authenticationProvider,
-            Credentials credentials) {
+            Credentials credentials, Set<String> effectiveGroups) {
         this.authenticationProvider = authenticationProvider;
         this.credentials = credentials;
         this.remoteHost = credentials.getRemoteAddress();
+        this.effectiveGroups = Collections.unmodifiableSet(effectiveGroups);
     }
 
     @Override
@@ -76,6 +89,11 @@ public abstract class RemoteAuthenticatedUser implements AuthenticatedUser {
     }
 
     @Override
+    public Set<String> getEffectiveUserGroups() {
+        return effectiveGroups;
+    }
+
+    @Override
     public AuthenticationProvider getAuthenticationProvider() {
         return authenticationProvider;
     }


[16/38] guacamole-client git commit: GUACAMOLE-220: Map and query user group tables.

Posted by vn...@apache.org.
GUACAMOLE-220: Map and query user group tables.


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

Branch: refs/heads/master
Commit: c5c2984151cc63ab278eb0884a225fd785c9d03f
Parents: 69f58c8
Author: Michael Jumper <mj...@apache.org>
Authored: Sun Apr 8 00:08:36 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:52 2018 -0700

----------------------------------------------------------------------
 .../jdbc/JDBCAuthenticationProviderModule.java  |  14 ++
 .../auth/jdbc/base/ModeledPermissions.java      |  15 +-
 .../permission/UserGroupPermissionMapper.java   |  25 ++
 .../permission/UserGroupPermissionService.java  |  67 ++++++
 .../jdbc/permission/UserGroupPermissionSet.java |  42 ++++
 .../auth/jdbc/user/ModeledUserContext.java      |  16 +-
 .../auth/jdbc/usergroup/ModeledUserGroup.java   | 191 ++++++++++++++++
 .../auth/jdbc/usergroup/UserGroupDirectory.java |  82 +++++++
 .../auth/jdbc/usergroup/UserGroupMapper.java    |  42 ++++
 .../auth/jdbc/usergroup/UserGroupModel.java     |  68 ++++++
 .../auth/jdbc/usergroup/UserGroupService.java   | 189 +++++++++++++++
 .../permission/UserGroupPermissionMapper.xml    | 156 +++++++++++++
 .../auth/jdbc/usergroup/UserGroupMapper.xml     | 229 +++++++++++++++++++
 13 files changed, 1127 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c5c29841/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
index 48c95c7..b97e7e4 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
@@ -65,6 +65,9 @@ import org.apache.guacamole.auth.jdbc.connection.ConnectionParameterMapper;
 import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionMapper;
 import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService;
 import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionSet;
+import org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionMapper;
+import org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionService;
+import org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionSet;
 import org.apache.guacamole.auth.jdbc.security.PasswordPolicyService;
 import org.apache.guacamole.auth.jdbc.sharing.ConnectionSharingService;
 import org.apache.guacamole.auth.jdbc.sharing.HashSharedConnectionMap;
@@ -79,6 +82,10 @@ import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileService;
 import org.apache.guacamole.auth.jdbc.tunnel.RestrictedGuacamoleTunnelService;
 import org.apache.guacamole.auth.jdbc.user.PasswordRecordMapper;
 import org.apache.guacamole.auth.jdbc.user.UserRecordMapper;
+import org.apache.guacamole.auth.jdbc.usergroup.ModeledUserGroup;
+import org.apache.guacamole.auth.jdbc.usergroup.UserGroupDirectory;
+import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMapper;
+import org.apache.guacamole.auth.jdbc.usergroup.UserGroupService;
 import org.mybatis.guice.MyBatisModule;
 import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider;
 
@@ -128,6 +135,8 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
         addMapperClass(SharingProfileMapper.class);
         addMapperClass(SharingProfileParameterMapper.class);
         addMapperClass(SharingProfilePermissionMapper.class);
+        addMapperClass(UserGroupMapper.class);
+        addMapperClass(UserGroupPermissionMapper.class);
         addMapperClass(UserMapper.class);
         addMapperClass(UserPermissionMapper.class);
         addMapperClass(UserRecordMapper.class);
@@ -146,12 +155,15 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
         bind(ModeledSharingProfile.class);
         bind(ModeledUser.class);
         bind(ModeledUserContext.class);
+        bind(ModeledUserGroup.class);
         bind(RootConnectionGroup.class);
         bind(SharingProfileDirectory.class);
         bind(SharingProfilePermissionSet.class);
         bind(SystemPermissionSet.class);
         bind(TrackedActiveConnection.class);
         bind(UserDirectory.class);
+        bind(UserGroupDirectory.class);
+        bind(UserGroupPermissionSet.class);
         bind(UserPermissionSet.class);
         
         // Bind services
@@ -172,6 +184,8 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
         bind(SharingProfilePermissionService.class);
         bind(SharingProfileService.class);
         bind(SystemPermissionService.class);
+        bind(UserGroupService.class);
+        bind(UserGroupPermissionService.class);
         bind(UserPermissionService.class);
         bind(UserService.class);
         

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c5c29841/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledPermissions.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledPermissions.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledPermissions.java
index 2f7808d..cda6f6a 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledPermissions.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledPermissions.java
@@ -28,13 +28,13 @@ import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissio
 import org.apache.guacamole.auth.jdbc.permission.ConnectionGroupPermissionService;
 import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionService;
 import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService;
+import org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionService;
 import org.apache.guacamole.auth.jdbc.permission.UserPermissionService;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
 import org.apache.guacamole.net.auth.Permissions;
 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.net.auth.simple.SimpleObjectPermissionSet;
 
 /**
  * An implementation of the base Permissions interface which is common to both
@@ -89,6 +89,12 @@ public abstract class ModeledPermissions<ModelType extends EntityModel>
     private UserPermissionService userPermissionService;
 
     /**
+     * Service for retrieving user group permissions.
+     */
+    @Inject
+    private UserGroupPermissionService userGroupPermissionService;
+
+    /**
      * Returns whether the underlying entity is a user. Entities may be either
      * users or user groups.
      *
@@ -171,8 +177,8 @@ public abstract class ModeledPermissions<ModelType extends EntityModel>
 
     @Override
     public ObjectPermissionSet getUserGroupPermissions() throws GuacamoleException {
-        // FIXME: STUB
-        return new SimpleObjectPermissionSet();
+        return userGroupPermissionService.getPermissionSet(getCurrentUser(),
+                this, Collections.<String>emptySet());
     }
 
     /**
@@ -256,8 +262,7 @@ public abstract class ModeledPermissions<ModelType extends EntityModel>
             @Override
             public ObjectPermissionSet getUserGroupPermissions()
                     throws GuacamoleException {
-                // FIXME: STUB
-                return new SimpleObjectPermissionSet();
+                return userGroupPermissionService.getPermissionSet(getCurrentUser(), ModeledPermissions.this, effectiveGroups);
             }
 
         };

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c5c29841/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.java
new file mode 100644
index 0000000..d2a7494
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.java
@@ -0,0 +1,25 @@
+/*
+ * 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.permission;
+
+/**
+ * Mapper for user group permissions.
+ */
+public interface UserGroupPermissionMapper extends ObjectPermissionMapper {}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c5c29841/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionService.java
new file mode 100644
index 0000000..852b9f0
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionService.java
@@ -0,0 +1,67 @@
+/*
+ * 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.permission;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import java.util.Set;
+import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
+import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
+
+/**
+ * Service which provides convenience methods for creating, retrieving, and
+ * deleting user group permissions. This service will automatically enforce the
+ * permissions of the current user.
+ */
+public class UserGroupPermissionService extends ModeledObjectPermissionService {
+
+    /**
+     * Mapper for user group permissions.
+     */
+    @Inject
+    private UserGroupPermissionMapper userGroupPermissionMapper;
+    
+    /**
+     * Provider for user group permission sets.
+     */
+    @Inject
+    private Provider<UserGroupPermissionSet> userGroupPermissionSetProvider;
+    
+    @Override
+    protected ObjectPermissionMapper getPermissionMapper() {
+        return userGroupPermissionMapper;
+    }
+
+    @Override
+    public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            Set<String> effectiveGroups) throws GuacamoleException {
+
+        // Create permission set for requested entity
+        ObjectPermissionSet permissionSet = userGroupPermissionSetProvider.get();
+        permissionSet.init(user, targetEntity, effectiveGroups);
+
+        return permissionSet;
+        
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c5c29841/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionSet.java
new file mode 100644
index 0000000..a864144
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionSet.java
@@ -0,0 +1,42 @@
+/*
+ * 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.permission;
+
+import com.google.inject.Inject;
+
+/**
+ * A database implementation of ObjectPermissionSet which uses an injected
+ * service to query and manipulate the user group permissions associated with a
+ * particular user.
+ */
+public class UserGroupPermissionSet extends ObjectPermissionSet {
+
+    /**
+     * Service for querying and manipulating user group permissions.
+     */
+    @Inject
+    private UserGroupPermissionService userGroupPermissionService;
+    
+    @Override
+    protected ObjectPermissionService getObjectPermissionService() {
+        return userGroupPermissionService;
+    }
+ 
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c5c29841/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
index d53164b..e98a25a 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUserContext.java
@@ -26,7 +26,6 @@ import org.apache.guacamole.auth.jdbc.connection.ConnectionDirectory;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Date;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
@@ -37,6 +36,8 @@ import org.apache.guacamole.auth.jdbc.connection.ModeledConnection;
 import org.apache.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup;
 import org.apache.guacamole.auth.jdbc.sharingprofile.ModeledSharingProfile;
 import org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileDirectory;
+import org.apache.guacamole.auth.jdbc.usergroup.ModeledUserGroup;
+import org.apache.guacamole.auth.jdbc.usergroup.UserGroupDirectory;
 import org.apache.guacamole.form.Form;
 import org.apache.guacamole.net.auth.ActiveConnection;
 import org.apache.guacamole.net.auth.ActivityRecord;
@@ -48,7 +49,6 @@ 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.UserGroup;
-import org.apache.guacamole.net.auth.simple.SimpleDirectory;
 
 /**
  * UserContext implementation which is driven by an arbitrary, underlying
@@ -63,6 +63,13 @@ public class ModeledUserContext extends RestrictedObject
      */
     @Inject
     private UserDirectory userDirectory;
+
+    /**
+     * User group directory restricted by the permissions of the user associated
+     * with this context.
+     */
+    @Inject
+    private UserGroupDirectory userGroupDirectory;
  
     /**
      * Connection directory restricted by the permissions of the user
@@ -128,6 +135,7 @@ public class ModeledUserContext extends RestrictedObject
         
         // Init directories
         userDirectory.init(currentUser);
+        userGroupDirectory.init(currentUser);
         connectionDirectory.init(currentUser);
         connectionGroupDirectory.init(currentUser);
         sharingProfileDirectory.init(currentUser);
@@ -166,7 +174,7 @@ public class ModeledUserContext extends RestrictedObject
 
     @Override
     public Directory<UserGroup> getUserGroupDirectory() throws GuacamoleException {
-        return new SimpleDirectory<UserGroup>();
+        return userGroupDirectory;
     }
 
     @Override
@@ -224,7 +232,7 @@ public class ModeledUserContext extends RestrictedObject
 
     @Override
     public Collection<Form> getUserGroupAttributes() {
-        return Collections.<Form>emptyList();
+        return ModeledUserGroup.ATTRIBUTES;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c5c29841/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
new file mode 100644
index 0000000..470bfab
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
@@ -0,0 +1,191 @@
+/*
+ * 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.usergroup;
+
+import com.google.inject.Inject;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
+import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
+import org.apache.guacamole.form.BooleanField;
+import org.apache.guacamole.form.Field;
+import org.apache.guacamole.form.Form;
+import org.apache.guacamole.net.auth.RelatedObjectSet;
+import org.apache.guacamole.net.auth.UserGroup;
+import org.apache.guacamole.net.auth.simple.SimpleRelatedObjectSet;
+
+/**
+ * An implementation of the UserGroup object which is backed by a database model.
+ */
+public class ModeledUserGroup extends ModeledPermissions<UserGroupModel>
+        implements UserGroup {
+
+    /**
+     * The name of the attribute which controls whether a user group is
+     * disabled.
+     */
+    public static final String DISABLED_ATTRIBUTE_NAME = "disabled";
+
+    /**
+     * All attributes related to restricting user groups, within a logical
+     * form.
+     */
+    public static final Form ACCOUNT_RESTRICTIONS = new Form("restrictions", Arrays.<Field>asList(
+        new BooleanField(DISABLED_ATTRIBUTE_NAME, "true")
+    ));
+
+    /**
+     * All possible attributes of user groups organized as individual,
+     * logical forms.
+     */
+    public static final Collection<Form> ATTRIBUTES = Collections.unmodifiableCollection(Arrays.asList(
+        ACCOUNT_RESTRICTIONS
+    ));
+
+    /**
+     * The names of all attributes which are explicitly supported by this
+     * extension's UserGroup objects.
+     */
+    public static final Set<String> ATTRIBUTE_NAMES =
+            Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
+                DISABLED_ATTRIBUTE_NAME
+            )));
+
+    /**
+     * Service for managing user groups.
+     */
+    @Inject
+    private UserGroupService userGroupService;
+
+    /**
+     * Whether attributes which control access restrictions should be exposed
+     * via getAttributes() or allowed to be set via setAttributes().
+     */
+    private boolean exposeRestrictedAttributes = false;
+
+    /**
+     * Initializes this ModeledUserGroup, associating it with the current
+     * authenticated user and populating it with data from the given user group
+     * model.
+     *
+     * @param currentUser
+     *     The user that created or retrieved this object.
+     *
+     * @param model
+     *     The backing model object.
+     *
+     * @param exposeRestrictedAttributes
+     *     Whether attributes which control access restrictions should be
+     *     exposed via getAttributes() or allowed to be set via
+     *     setAttributes().
+     */
+    public void init(ModeledAuthenticatedUser currentUser, UserGroupModel model,
+            boolean exposeRestrictedAttributes) {
+        super.init(currentUser, model);
+        this.exposeRestrictedAttributes = exposeRestrictedAttributes;
+    }
+
+    /**
+     * Creates a new, empty ModeledUserGroup.
+     */
+    public ModeledUserGroup() {
+    }
+
+    /**
+     * Stores all restricted (privileged) attributes within the given Map,
+     * pulling the values of those attributes from the underlying user group
+     * model. If no value is yet defined for an attribute, that attribute will
+     * be set to null.
+     *
+     * @param attributes
+     *     The Map to store all restricted attributes within.
+     */
+    private void putRestrictedAttributes(Map<String, String> attributes) {
+
+        // Set disabled attribute
+        attributes.put(DISABLED_ATTRIBUTE_NAME, getModel().isDisabled() ? "true" : null);
+
+    }
+
+    /**
+     * Stores all restricted (privileged) attributes within the underlying user
+     * group model, pulling the values of those attributes from the given Map.
+     *
+     * @param attributes
+     *     The Map to pull all restricted attributes from.
+     */
+    private void setRestrictedAttributes(Map<String, String> attributes) {
+
+        // Translate disabled attribute
+        getModel().setDisabled("true".equals(attributes.get(DISABLED_ATTRIBUTE_NAME)));
+
+    }
+
+    @Override
+    public Set<String> getSupportedAttributeNames() {
+        return ATTRIBUTE_NAMES;
+    }
+
+    @Override
+    public Map<String, String> getAttributes() {
+
+        // Include any defined arbitrary attributes
+        Map<String, String> attributes = super.getAttributes();
+
+        // Include restricted attributes only if they should be exposed
+        if (exposeRestrictedAttributes)
+            putRestrictedAttributes(attributes);
+
+        return attributes;
+    }
+
+    @Override
+    public void setAttributes(Map<String, String> attributes) {
+
+        // Set arbitrary attributes
+        super.setAttributes(attributes);
+
+        // Assign restricted attributes only if they are exposed
+        if (exposeRestrictedAttributes)
+            setRestrictedAttributes(attributes);
+
+    }
+
+    @Override
+    public RelatedObjectSet getUserGroups() throws GuacamoleException {
+        return new SimpleRelatedObjectSet();
+    }
+
+    @Override
+    public RelatedObjectSet getMemberUsers() throws GuacamoleException {
+        return new SimpleRelatedObjectSet();
+    }
+
+    @Override
+    public RelatedObjectSet getMemberUserGroups() throws GuacamoleException {
+        return new SimpleRelatedObjectSet();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c5c29841/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupDirectory.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupDirectory.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupDirectory.java
new file mode 100644
index 0000000..911b852
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupDirectory.java
@@ -0,0 +1,82 @@
+/*
+ * 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.usergroup;
+
+import com.google.inject.Inject;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
+import org.apache.guacamole.net.auth.Directory;
+import org.apache.guacamole.net.auth.UserGroup;
+import org.mybatis.guice.transactional.Transactional;
+
+/**
+ * Implementation of the UserGroup Directory which is driven by an underlying,
+ * arbitrary database.
+ */
+public class UserGroupDirectory extends RestrictedObject
+    implements Directory<UserGroup> {
+
+    /**
+     * Service for managing user group objects.
+     */
+    @Inject
+    private UserGroupService userGroupService;
+
+    @Override
+    public UserGroup get(String identifier) throws GuacamoleException {
+        return userGroupService.retrieveObject(getCurrentUser(), identifier);
+    }
+
+    @Override
+    @Transactional
+    public Collection<UserGroup> getAll(Collection<String> identifiers) throws GuacamoleException {
+        Collection<ModeledUserGroup> objects = userGroupService.retrieveObjects(getCurrentUser(), identifiers);
+        return Collections.<UserGroup>unmodifiableCollection(objects);
+    }
+
+    @Override
+    @Transactional
+    public Set<String> getIdentifiers() throws GuacamoleException {
+        return userGroupService.getIdentifiers(getCurrentUser());
+    }
+
+    @Override
+    @Transactional
+    public void add(UserGroup object) throws GuacamoleException {
+        userGroupService.createObject(getCurrentUser(), object);
+    }
+
+    @Override
+    @Transactional
+    public void update(UserGroup object) throws GuacamoleException {
+        ModeledUserGroup group = (ModeledUserGroup) object;
+        userGroupService.updateObject(getCurrentUser(), group);
+    }
+
+    @Override
+    @Transactional
+    public void remove(String identifier) throws GuacamoleException {
+        userGroupService.deleteObject(getCurrentUser(), identifier);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c5c29841/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.java
new file mode 100644
index 0000000..7c048f7
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.java
@@ -0,0 +1,42 @@
+/*
+ * 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.usergroup;
+
+import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * Mapper for user group objects.
+ */
+public interface UserGroupMapper extends ModeledDirectoryObjectMapper<UserGroupModel> {
+
+    /**
+     * Returns the group having the given name, if any. If no such group
+     * exists, null is returned.
+     *
+     * @param name
+     *     The name of the group to return.
+     *
+     * @return
+     *     The group having the given name, or null if no such group exists.
+     */
+    UserGroupModel selectOne(@Param("name") String name);
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c5c29841/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupModel.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupModel.java
new file mode 100644
index 0000000..7fb9c8c
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupModel.java
@@ -0,0 +1,68 @@
+/*
+ * 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.usergroup;
+
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
+import org.apache.guacamole.auth.jdbc.base.EntityType;
+
+/**
+ * Object representation of a Guacamole user group, as represented in the
+ * database.
+ */
+public class UserGroupModel extends EntityModel {
+
+    /**
+     * Whether the user group is disabled. Disabled accounts exist and can
+     * be modified, but cannot be used.
+     */
+    private boolean disabled;
+
+    /**
+     * Creates a new, empty user group.
+     */
+    public UserGroupModel() {
+        super(EntityType.USER_GROUP);
+    }
+
+    /**
+     * Returns whether this user group has been disabled. Memberships of
+     * disabled user groups are treated as non-existent, effectively disabling
+     * membership in that group.
+     *
+     * @return
+     *     true if this user group is disabled, false otherwise.
+     */
+    public boolean isDisabled() {
+        return disabled;
+    }
+
+    /**
+     * Sets whether this user group has been disabled. Memberships of disabled
+     * user groups are treated as non-existent, effectively disabling
+     * membership in that group.
+     *
+     * @param disabled
+     *     true if this user group should be disabled, false otherwise.
+     */
+    public void setDisabled(boolean disabled) {
+        this.disabled = disabled;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c5c29841/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupService.java
new file mode 100644
index 0000000..dfe1ef5
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupService.java
@@ -0,0 +1,189 @@
+/*
+ * 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.usergroup;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import java.util.Collection;
+import java.util.Collections;
+import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
+import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectService;
+import org.apache.guacamole.GuacamoleClientException;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.base.EntityMapper;
+import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
+import org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionMapper;
+import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
+import org.apache.guacamole.net.auth.UserGroup;
+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;
+
+/**
+ * Service which provides convenience methods for creating, retrieving, and
+ * manipulating user groups.
+ */
+public class UserGroupService extends ModeledDirectoryObjectService<ModeledUserGroup, UserGroup, UserGroupModel> {
+    
+    /**
+     * Mapper for creating/deleting entities.
+     */
+    @Inject
+    private EntityMapper entityMapper;
+
+    /**
+     * Mapper for accessing user groups.
+     */
+    @Inject
+    private UserGroupMapper userGroupMapper;
+
+    /**
+     * Mapper for manipulating user group permissions.
+     */
+    @Inject
+    private UserGroupPermissionMapper userGroupPermissionMapper;
+
+    /**
+     * Provider for creating user groups.
+     */
+    @Inject
+    private Provider<ModeledUserGroup> userGroupProvider;
+
+    @Override
+    protected ModeledDirectoryObjectMapper<UserGroupModel> getObjectMapper() {
+        return userGroupMapper;
+    }
+
+    @Override
+    protected ObjectPermissionMapper getPermissionMapper() {
+        return userGroupPermissionMapper;
+    }
+
+    @Override
+    protected ModeledUserGroup getObjectInstance(ModeledAuthenticatedUser currentUser,
+            UserGroupModel model) throws GuacamoleException {
+
+        boolean exposeRestrictedAttributes;
+
+        // Expose restricted attributes if the user group does not yet exist
+        if (model.getObjectID() == null)
+            exposeRestrictedAttributes = true;
+
+        // Otherwise, expose restricted attributes only if the user has
+        // ADMINISTER permission
+        else
+            exposeRestrictedAttributes = hasObjectPermission(currentUser,
+                    model.getIdentifier(), ObjectPermission.Type.ADMINISTER);
+
+        // Produce ModeledUserGroup exposing only those attributes for which the
+        // current user has permission
+        ModeledUserGroup group = userGroupProvider.get();
+        group.init(currentUser, model, exposeRestrictedAttributes);
+        return group;
+
+    }
+
+    @Override
+    protected UserGroupModel getModelInstance(ModeledAuthenticatedUser currentUser,
+            final UserGroup object) throws GuacamoleException {
+
+        // Create new ModeledUserGroup backed by blank model
+        UserGroupModel model = new UserGroupModel();
+        ModeledUserGroup group = getObjectInstance(currentUser, model);
+
+        // Set model contents through ModeledUser, copying the provided group
+        group.setIdentifier(object.getIdentifier());
+        group.setAttributes(object.getAttributes());
+
+        return model;
+        
+    }
+
+    @Override
+    protected boolean hasCreatePermission(ModeledAuthenticatedUser user)
+            throws GuacamoleException {
+
+        // Return whether user has explicit user group creation permission
+        SystemPermissionSet permissionSet = user.getUser().getEffectivePermissions().getSystemPermissions();
+        return permissionSet.hasPermission(SystemPermission.Type.CREATE_USER);
+
+    }
+
+    @Override
+    protected ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
+            throws GuacamoleException {
+
+        // Return permissions related to user groups
+        return user.getUser().getEffectivePermissions().getUserGroupPermissions();
+
+    }
+
+    @Override
+    protected void beforeCreate(ModeledAuthenticatedUser user, UserGroup object,
+            UserGroupModel model) throws GuacamoleException {
+
+        super.beforeCreate(user, object, model);
+        
+        // Group name must not be blank
+        if (model.getIdentifier() == null || model.getIdentifier().trim().isEmpty())
+            throw new GuacamoleClientException("The group name must not be blank.");
+        
+        // Do not create duplicate user groups
+        Collection<UserGroupModel> existing = userGroupMapper.select(Collections.singleton(model.getIdentifier()));
+        if (!existing.isEmpty())
+            throw new GuacamoleClientException("Group \"" + model.getIdentifier() + "\" already exists.");
+
+        // Create base entity object, implicitly populating underlying entity ID
+        entityMapper.insert(model);
+
+    }
+
+    @Override
+    protected void beforeUpdate(ModeledAuthenticatedUser user,
+            ModeledUserGroup object, UserGroupModel model) throws GuacamoleException {
+
+        super.beforeUpdate(user, object, model);
+        
+        // Username must not be blank
+        if (model.getIdentifier() == null || model.getIdentifier().trim().isEmpty())
+            throw new GuacamoleClientException("The group name must not be blank.");
+        
+        // Check whether such a group is already present
+        UserGroupModel existing = userGroupMapper.selectOne(model.getIdentifier());
+        if (existing != null) {
+
+            // Do not rename to existing user group
+            if (!existing.getObjectID().equals(model.getObjectID()))
+                throw new GuacamoleClientException("Group \"" + model.getIdentifier() + "\" already exists.");
+            
+        }
+
+    }
+
+    @Override
+    protected boolean isValidIdentifier(String identifier) {
+
+        // All strings are valid group identifiers
+        return true;
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c5c29841/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml
new file mode 100644
index 0000000..44ac201
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml
@@ -0,0 +1,156 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionMapper" >
+
+    <!-- Result mapper for user group permissions -->
+    <resultMap id="UserGroupPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
+        <result column="entity_id"         property="entityID"         jdbcType="INTEGER"/>
+        <result column="permission"        property="type"             jdbcType="VARCHAR"
+                javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
+        <result column="affected_name"     property="objectIdentifier" jdbcType="INTEGER"/>
+    </resultMap>
+
+    <!-- Select all permissions for a given entity -->
+    <select id="select" resultMap="UserGroupPermissionResultMap">
+
+        SELECT
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
+            permission,
+            affected_entity.name AS affected_name
+        FROM guacamole_user_group_permission
+        JOIN guacamole_user_group affected_group ON guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id
+        JOIN guacamole_entity affected_entity ON affected_group.entity_id = affected_entity.entity_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_group_permission.entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND affected_entity.type = 'USER_GROUP'::guacamole_entity_type
+
+    </select>
+
+    <!-- Select the single permission matching the given criteria -->
+    <select id="selectOne" resultMap="UserGroupPermissionResultMap">
+
+        SELECT
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
+            permission,
+            affected_entity.name AS affected_name
+        FROM guacamole_user_group_permission
+        JOIN guacamole_user_group affected_group ON guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id
+        JOIN guacamole_entity affected_entity ON affected_group.entity_id = affected_entity.entity_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_group_permission.entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
+            AND affected_entity.name = #{identifier,jdbcType=VARCHAR}
+            AND affected_entity.type = 'USER_GROUP'::guacamole_entity_type
+
+    </select>
+
+    <!-- Select identifiers accessible by the given entity for the given permissions -->
+    <select id="selectAccessibleIdentifiers" resultType="string">
+
+        SELECT DISTINCT affected_entity.name
+        FROM guacamole_user_group_permission
+        JOIN guacamole_user_group affected_group ON guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id
+        JOIN guacamole_entity affected_entity ON affected_group.entity_id = affected_entity.entity_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_group_permission.entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND affected_entity.name IN
+                <foreach collection="identifiers" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+            AND permission IN
+                <foreach collection="permissions" item="permission"
+                         open="(" separator="," close=")">
+                    #{permission,jdbcType=VARCHAR}::guacamole_object_permission_type
+                </foreach>
+            AND affected_entity.type = 'USER_GROUP'::guacamole_entity_type
+
+    </select>
+
+    <!-- Delete all given permissions -->
+    <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
+
+        DELETE FROM guacamole_user_group_permission
+        USING guacamole_user_group affected_group, guacamole_entity affected_entity
+        WHERE
+            guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id
+            AND affected_group.entity_id = affected_entity.entity_id
+            AND (guacamole_user_group_permission.entity_id, permission, affected_entity.name) IN
+                <foreach collection="permissions" item="permission"
+                         open="(" separator="," close=")">
+                    (#{permission.entityID,jdbcType=INTEGER},
+                     #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type,
+                     #{permission.objectIdentifier,jdbcType=INTEGER})
+                </foreach>
+            AND affected_entity.type = 'USER_GROUP'::guacamole_entity_type
+
+    </delete>
+
+    <!-- Insert all given permissions -->
+    <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
+
+        INSERT INTO guacamole_user_group_permission (
+            entity_id,
+            permission,
+            affected_user_group_id
+        )
+        SELECT DISTINCT
+            permissions.entity_id,
+            permissions.permission,
+            affected_group.user_group_id
+        FROM
+            <foreach collection="permissions" item="permission"
+                     open="(" separator="UNION ALL" close=")">
+                SELECT #{permission.entityID,jdbcType=INTEGER}                               AS entity_id,
+                       #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type AS permission,
+                       #{permission.objectIdentifier,jdbcType=VARCHAR}::text                 AS affected_name
+            </foreach>
+        AS permissions
+        JOIN guacamole_entity affected_entity ON
+                affected_entity.name = permissions.affected_name
+            AND affected_entity.type = 'USER_GROUP'::guacamole_entity_type
+        JOIN guacamole_user_group affected_group ON affected_group.entity_id = affected_entity.entity_id
+        WHERE (permissions.entity_id, permissions.permission, affected_group.user_group_id) NOT IN (
+            SELECT
+                guacamole_user_group_permission.entity_id,
+                guacamole_user_group_permission.permission,
+                guacamole_user_group_permission.affected_user_group_id
+            FROM guacamole_user_group_permission
+        );
+
+    </insert>
+
+</mapper>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c5c29841/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml
new file mode 100644
index 0000000..0006d42
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.usergroup.UserGroupMapper" >
+
+    <!-- Result mapper for user group objects -->
+    <resultMap id="UserGroupResultMap" type="org.apache.guacamole.auth.jdbc.usergroup.UserGroupModel" >
+
+        <!-- User group properties -->
+        <id     column="user_group_id" property="objectID"   jdbcType="INTEGER"/>
+        <result column="entity_id"     property="entityID"   jdbcType="INTEGER"/>
+        <result column="name"          property="identifier" jdbcType="VARCHAR"/>
+        <result column="disabled"      property="disabled"   jdbcType="BOOLEAN"/>
+
+        <!-- Arbitrary attributes -->
+        <collection property="arbitraryAttributes" resultSet="arbitraryAttributes"
+                    ofType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel"
+                    column="user_group_id" foreignColumn="user_group_id">
+            <result property="name"     column="attribute_name"  jdbcType="VARCHAR"/>
+            <result property="value"    column="attribute_value" jdbcType="VARCHAR"/>
+        </collection>
+
+    </resultMap>
+
+    <!-- Select all group names -->
+    <select id="selectIdentifiers" resultType="string">
+        SELECT name
+        FROM guacamole_entity
+        WHERE guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type
+    </select>
+
+    <!-- Select names of all readable groups -->
+    <select id="selectReadableIdentifiers" resultType="string">
+        SELECT guacamole_entity.name
+        FROM guacamole_user_group
+        JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        JOIN guacamole_user_group_permission ON affected_user_group_id = guacamole_user_group.user_group_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_group_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type
+            AND permission = 'READ'
+    </select>
+
+    <!-- Select multiple groups by name -->
+    <select id="select" resultMap="UserGroupResultMap"
+            resultSets="users,arbitraryAttributes">
+
+        SELECT
+            guacamole_user_group.user_group_id,
+            guacamole_entity.entity_id,
+            guacamole_entity.name,
+            disabled
+        FROM guacamole_user_group
+        JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        WHERE guacamole_entity.name IN
+            <foreach collection="identifiers" item="identifier"
+                     open="(" separator="," close=")">
+                #{identifier,jdbcType=VARCHAR}
+            </foreach>
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type;
+
+        SELECT
+            guacamole_user_group_attribute.user_group_id,
+            guacamole_user_group_attribute.attribute_name,
+            guacamole_user_group_attribute.attribute_value
+        FROM guacamole_user_group_attribute
+        JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_attribute.user_group_id
+        JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        WHERE guacamole_entity.name IN
+            <foreach collection="identifiers" item="identifier"
+                     open="(" separator="," close=")">
+                #{identifier,jdbcType=VARCHAR}
+            </foreach>
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type;
+
+    </select>
+
+    <!-- Select multiple groups by name only if readable -->
+    <select id="selectReadable" resultMap="UserGroupResultMap"
+            resultSets="users,arbitraryAttributes">
+
+        SELECT
+            guacamole_user_group.user_group_id,
+            guacamole_entity.entity_id,
+            guacamole_entity.name,
+            disabled
+        FROM guacamole_user_group
+        JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        JOIN guacamole_user_group_permission ON affected_user_group_id = guacamole_user_group.user_group_id
+        WHERE guacamole_entity.name IN
+            <foreach collection="identifiers" item="identifier"
+                     open="(" separator="," close=")">
+                #{identifier,jdbcType=VARCHAR}
+            </foreach>
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_group_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND permission = 'READ';
+
+        SELECT
+            guacamole_user_group_attribute.user_group_id,
+            guacamole_user_group_attribute.attribute_name,
+            guacamole_user_group_attribute.attribute_value
+        FROM guacamole_user_group_attribute
+        JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_attribute.user_group_id
+        JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        JOIN guacamole_user_group_permission ON affected_user_group_id = guacamole_user_group.user_group_id
+        WHERE guacamole_entity.name IN
+            <foreach collection="identifiers" item="identifier"
+                     open="(" separator="," close=")">
+                #{identifier,jdbcType=VARCHAR}
+            </foreach>
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_group_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND permission = 'READ';
+
+    </select>
+
+    <!-- Select single group by name -->
+    <select id="selectOne" resultMap="UserGroupResultMap"
+            resultSets="users,arbitraryAttributes">
+
+        SELECT
+            guacamole_user_group.user_group_id,
+            guacamole_entity.entity_id,
+            guacamole_entity.name,
+            disabled
+        FROM guacamole_user_group
+        JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        WHERE
+            guacamole_entity.name = #{name,jdbcType=VARCHAR}
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type;
+
+        SELECT
+            guacamole_user_group_attribute.user_group_id,
+            guacamole_user_group_attribute.attribute_name,
+            guacamole_user_group_attribute.attribute_value
+        FROM guacamole_user_group_attribute
+        JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_attribute.user_group_id
+        JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        WHERE
+            guacamole_entity.name = #{name,jdbcType=VARCHAR}
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type
+
+    </select>
+
+    <!-- Delete single group by name -->
+    <delete id="delete">
+        DELETE FROM guacamole_entity
+        WHERE
+            name = #{identifier,jdbcType=VARCHAR}
+            AND type = 'USER_GROUP'::guacamole_entity_type
+    </delete>
+
+    <!-- Insert single group -->
+    <insert id="insert" useGeneratedKeys="true" keyProperty="object.objectID"
+            parameterType="org.apache.guacamole.auth.jdbc.usergroup.UserGroupModel">
+
+        INSERT INTO guacamole_user_group (
+            entity_id,
+            disabled
+        )
+        VALUES (
+            #{object.entityID,jdbcType=VARCHAR},
+            #{object.disabled,jdbcType=BOOLEAN}
+        )
+
+    </insert>
+
+    <!-- Update single group -->
+    <update id="update" parameterType="org.apache.guacamole.auth.jdbc.usergroup.UserGroupModel">
+        UPDATE guacamole_user_group
+        SET disabled = #{object.disabled,jdbcType=BOOLEAN}
+        WHERE user_group_id = #{object.objectID,jdbcType=VARCHAR}
+    </update>
+
+    <!-- Delete attributes associated with group -->
+    <delete id="deleteAttributes">
+        DELETE FROM guacamole_user_group_attribute
+        WHERE user_group_id = #{object.objectID,jdbcType=INTEGER}
+    </delete>
+
+    <!-- Insert attributes for group -->
+    <insert id="insertAttributes" parameterType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel">
+        INSERT INTO guacamole_user_group_attribute (
+            user_group_id,
+            attribute_name,
+            attribute_value
+        )
+        VALUES
+            <foreach collection="object.arbitraryAttributes" item="attribute" separator=",">
+                (#{object.objectID,jdbcType=INTEGER},
+                 #{attribute.name,jdbcType=VARCHAR},
+                 #{attribute.value,jdbcType=VARCHAR})
+            </foreach>
+    </insert>
+
+</mapper>


[32/38] guacamole-client git commit: GUACAMOLE-220: Remove unnecessary use of multi-result select (use selectOne() instead).

Posted by vn...@apache.org.
GUACAMOLE-220: Remove unnecessary use of multi-result select (use selectOne() instead).

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

Branch: refs/heads/master
Commit: 5fdd0bb14820954c2b39f991d4445b9e783149e2
Parents: a552d88
Author: Michael Jumper <mj...@apache.org>
Authored: Thu Sep 27 20:07:24 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Thu Sep 27 20:07:24 2018 -0700

----------------------------------------------------------------------
 .../apache/guacamole/auth/jdbc/usergroup/UserGroupService.java | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/5fdd0bb1/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupService.java
index 0f4a216..3c42572 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupService.java
@@ -21,8 +21,6 @@ package org.apache.guacamole.auth.jdbc.usergroup;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
-import java.util.Collection;
-import java.util.Collections;
 import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
 import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectService;
 import org.apache.guacamole.GuacamoleClientException;
@@ -147,8 +145,8 @@ public class UserGroupService extends ModeledDirectoryObjectService<ModeledUserG
             throw new GuacamoleClientException("The group name must not be blank.");
         
         // Do not create duplicate user groups
-        Collection<UserGroupModel> existing = userGroupMapper.select(Collections.singleton(model.getIdentifier()));
-        if (!existing.isEmpty())
+        UserGroupModel existing = userGroupMapper.selectOne(model.getIdentifier());
+        if (existing != null)
             throw new GuacamoleClientException("Group \"" + model.getIdentifier() + "\" already exists.");
 
         // Create base entity object, implicitly populating underlying entity ID


[21/38] guacamole-client git commit: GUACAMOLE-220: Map and allow manipulation of the user group parents of users.

Posted by vn...@apache.org.
GUACAMOLE-220: Map and allow manipulation of the user group parents of users.


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

Branch: refs/heads/master
Commit: 2999c560980d48bcf58befebbc6d9dde98db3a36
Parents: 856ab44
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Apr 10 15:18:38 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:52 2018 -0700

----------------------------------------------------------------------
 .../jdbc/JDBCAuthenticationProviderModule.java  |  2 +
 .../guacamole/auth/jdbc/user/ModeledUser.java   | 13 ++-
 .../jdbc/user/UserParentUserGroupMapper.java    | 28 ++++++
 .../auth/jdbc/user/UserParentUserGroupSet.java  | 59 ++++++++++++
 .../jdbc/user/UserParentUserGroupMapper.xml     | 96 ++++++++++++++++++++
 5 files changed, 196 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/2999c560/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
index 2d4c67a..5203cfe 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
@@ -91,6 +91,7 @@ import org.apache.guacamole.auth.jdbc.usergroup.UserGroupParentUserGroupMapper;
 import org.apache.guacamole.auth.jdbc.usergroup.UserGroupService;
 import org.mybatis.guice.MyBatisModule;
 import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider;
+import org.apache.guacamole.auth.jdbc.user.UserParentUserGroupMapper;
 
 /**
  * Guice module which configures the injections used by the JDBC authentication
@@ -144,6 +145,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
         addMapperClass(UserGroupParentUserGroupMapper.class);
         addMapperClass(UserGroupPermissionMapper.class);
         addMapperClass(UserMapper.class);
+        addMapperClass(UserParentUserGroupMapper.class);
         addMapperClass(UserPermissionMapper.class);
         addMapperClass(UserRecordMapper.class);
         

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/2999c560/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
index 9b65471..b7924ed 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
@@ -20,6 +20,7 @@
 package org.apache.guacamole.auth.jdbc.user;
 
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 import java.sql.Date;
 import java.sql.Time;
 import java.sql.Timestamp;
@@ -49,7 +50,6 @@ import org.apache.guacamole.net.auth.ActivityRecord;
 import org.apache.guacamole.net.auth.Permissions;
 import org.apache.guacamole.net.auth.RelatedObjectSet;
 import org.apache.guacamole.net.auth.User;
-import org.apache.guacamole.net.auth.simple.SimpleRelatedObjectSet;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -177,6 +177,13 @@ public class ModeledUser extends ModeledPermissions<UserModel> implements User {
     private SaltService saltService;
 
     /**
+     * Provider for RelatedObjectSets containing the user groups of which this
+     * user is a member.
+     */
+    @Inject
+    private Provider<UserParentUserGroupSet> parentUserGroupSetProvider;
+
+    /**
      * Whether attributes which control access restrictions should be exposed
      * via getAttributes() or allowed to be set via setAttributes().
      */
@@ -747,7 +754,9 @@ public class ModeledUser extends ModeledPermissions<UserModel> implements User {
 
     @Override
     public RelatedObjectSet getUserGroups() throws GuacamoleException {
-        return new SimpleRelatedObjectSet();
+        UserParentUserGroupSet parentUserGroupSet = parentUserGroupSetProvider.get();
+        parentUserGroupSet.init(getCurrentUser(), this);
+        return parentUserGroupSet;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/2999c560/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.java
new file mode 100644
index 0000000..ee3d6a8
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.java
@@ -0,0 +1,28 @@
+/*
+ * 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.user;
+
+import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper;
+
+/**
+ * Mapper for the one-to-many relationship between a user and the user groups
+ * of which it is a member.
+ */
+public interface UserParentUserGroupMapper extends ObjectRelationMapper<UserModel> {}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/2999c560/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupSet.java
new file mode 100644
index 0000000..f888729
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupSet.java
@@ -0,0 +1,59 @@
+/*
+ * 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.user;
+
+import com.google.inject.Inject;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper;
+import org.apache.guacamole.auth.jdbc.base.RelatedObjectSet;
+import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
+
+/**
+ * RelatedObjectSet implementation which represents the one-to-many
+ * relationship between a particular user and the user groups of which it is a
+ * member.
+ */
+public class UserParentUserGroupSet extends RelatedObjectSet<ModeledUser, UserModel> {
+
+    /**
+     * Mapper for the relations between users and the user groups of which they
+     * are members.
+     */
+    @Inject
+    private UserParentUserGroupMapper userParentUserGroupMapper;
+
+    @Override
+    protected ObjectRelationMapper<UserModel> getObjectRelationMapper() {
+        return userParentUserGroupMapper;
+    }
+
+    @Override
+    protected ObjectPermissionSet
+        getParentObjectEffectivePermissionSet() throws GuacamoleException {
+           return getCurrentUser().getUser().getEffectivePermissions().getUserPermissions();
+    }
+
+    @Override
+    protected ObjectPermissionSet getChildObjectEffectivePermissionSet()
+            throws GuacamoleException {
+        return getCurrentUser().getUser().getEffectivePermissions().getUserGroupPermissions();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/2999c560/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml
new file mode 100644
index 0000000..bcff7a2
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.user.UserParentUserGroupMapper" >
+
+    <!-- Select the names of all parent user groups -->
+    <select id="selectChildIdentifiers" resultType="string">
+        SELECT name
+        FROM guacamole_user_group_member
+        JOIN guacamole_user_group ON guacamole_user_group_member.user_group_id = guacamole_user_group.user_group_id
+        JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group.entity_id
+        WHERE
+            guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type
+    </select>
+
+    <!-- Select the names of all readable parent user groups -->
+    <select id="selectReadableChildIdentifiers" resultType="string">
+        SELECT guacamole_entity.name
+        FROM guacamole_user_group_member
+        JOIN guacamole_user_group ON guacamole_user_group_member.user_group_id = guacamole_user_group.user_group_id
+        JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group.entity_id
+        JOIN guacamole_user_group_permission ON affected_user_group_id = guacamole_user_group.user_group_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_group_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type
+            AND permission = 'READ'
+    </select>
+
+    <!-- Delete parent groups by name -->
+    <delete id="delete">
+        DELETE FROM guacamole_user_group_member
+        USING guacamole_user_group, guacamole_entity
+        WHERE
+            member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            AND guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
+            AND guacamole_entity.entity_id = guacamole_user_group.entity_id
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type
+            AND guacamole_entity.name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+    </delete>
+
+    <!-- Insert parent groups by name -->
+    <insert id="insert">
+        INSERT INTO guacamole_user_group_member (
+            user_group_id,
+            member_entity_id
+        )
+        SELECT DISTINCT
+            guacamole_user_group.user_group_id,
+            #{parent.entityID,jdbcType=INTEGER}
+        FROM guacamole_user_group
+        JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        WHERE
+            guacamole_entity.name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type
+            AND guacamole_user_group.user_group_id NOT IN (
+                SELECT guacamole_user_group_member.user_group_id
+                FROM guacamole_user_group_member
+                WHERE guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            )
+    </insert>
+
+</mapper>


[07/38] guacamole-client git commit: GUACAMOLE-220: Add explicit mapper for entities (the basis for users and groups).

Posted by vn...@apache.org.
GUACAMOLE-220: Add explicit mapper for entities (the basis for users and groups).


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

Branch: refs/heads/master
Commit: 72bac09f433de23654b66dbee0f2d5fd6a55e48c
Parents: b499092
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Apr 3 17:53:26 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:51 2018 -0700

----------------------------------------------------------------------
 .../jdbc/JDBCAuthenticationProviderModule.java  |  2 +
 .../guacamole/auth/jdbc/base/EntityMapper.java  | 43 ++++++++++++++++++++
 .../guacamole/auth/jdbc/user/UserService.java   | 10 +++++
 .../guacamole/auth/jdbc/base/EntityMapper.xml   | 41 +++++++++++++++++++
 4 files changed, 96 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/72bac09f/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
index 0f72559..17dfc5d 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
@@ -59,6 +59,7 @@ import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissio
 import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissionSet;
 import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionService;
 import org.apache.guacamole.auth.jdbc.activeconnection.TrackedActiveConnection;
+import org.apache.guacamole.auth.jdbc.base.EntityMapper;
 import org.apache.guacamole.auth.jdbc.connection.ConnectionParameterMapper;
 import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionMapper;
 import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService;
@@ -120,6 +121,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
         addMapperClass(ConnectionPermissionMapper.class);
         addMapperClass(ConnectionRecordMapper.class);
         addMapperClass(ConnectionParameterMapper.class);
+        addMapperClass(EntityMapper.class);
         addMapperClass(PasswordRecordMapper.class);
         addMapperClass(SystemPermissionMapper.class);
         addMapperClass(SharingProfileMapper.class);

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/72bac09f/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java
new file mode 100644
index 0000000..14657ce
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java
@@ -0,0 +1,43 @@
+/*
+ * 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.base;
+
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * Mapper for entities. An entity is the base concept behind a user or user
+ * group, and serves as a common point for granting permissions and defining
+ * group membership.
+ */
+public interface EntityMapper {
+
+    /**
+     * Inserts the given entity into the database. If the entity already
+     * exists, this will result in an error.
+     *
+     * @param entity
+     *     The entity to insert.
+     *
+     * @return
+     *     The number of rows inserted.
+     */
+    int insert(@Param("entity") EntityModel entity);
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/72bac09f/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
index e4bb738..9f7fb87 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
@@ -37,6 +37,7 @@ import org.apache.guacamole.GuacamoleUnsupportedException;
 import org.apache.guacamole.auth.jdbc.base.ActivityRecordModel;
 import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
 import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
+import org.apache.guacamole.auth.jdbc.base.EntityMapper;
 import org.apache.guacamole.auth.jdbc.base.ModeledActivityRecord;
 import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
 import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel;
@@ -114,6 +115,12 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
     ));
 
     /**
+     * Mapper for creating/deleting entities.
+     */
+    @Inject
+    private EntityMapper entityMapper;
+
+    /**
      * Mapper for accessing users.
      */
     @Inject
@@ -242,6 +249,9 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
         if (object.getPassword() != null)
             passwordPolicyService.verifyPassword(object.getIdentifier(), object.getPassword());
 
+        // Create base entity object, implicitly populating underlying entity ID
+        entityMapper.insert(model);
+
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/72bac09f/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
new file mode 100644
index 0000000..f05c287
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.base.EntityMapper" >
+
+    <!-- Insert single entity -->
+    <insert id="insert" useGeneratedKeys="true" keyProperty="entity.entityID"
+            parameterType="org.apache.guacamole.auth.jdbc.base.EntityModel">
+
+        INSERT INTO guacamole_entity (
+            name,
+            type
+        )
+        VALUES (
+            #{entity.identifier,jdbcType=VARCHAR},
+            #{entity.entityType,jdbcType=VARCHAR}::guacamole_entity_type
+        )
+
+    </insert>
+
+</mapper>


[20/38] guacamole-client git commit: GUACAMOLE-220: Map and allow manipulation of the user members of user groups.

Posted by vn...@apache.org.
GUACAMOLE-220: Map and allow manipulation of the user members of user groups.


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

Branch: refs/heads/master
Commit: ccd7920b2238de6d634336c3c6e2a8b13fa7d2f8
Parents: 8f06b7a
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Apr 10 13:16:34 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:52 2018 -0700

----------------------------------------------------------------------
 .../jdbc/JDBCAuthenticationProviderModule.java  |  2 +
 .../auth/jdbc/usergroup/ModeledUserGroup.java   | 10 ++-
 .../usergroup/UserGroupMemberUserMapper.java    | 28 ++++++
 .../jdbc/usergroup/UserGroupMemberUserSet.java  | 57 ++++++++++++
 .../usergroup/UserGroupMemberUserMapper.xml     | 93 ++++++++++++++++++++
 5 files changed, 187 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ccd7920b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
index b97e7e4..0750b10 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
@@ -85,6 +85,7 @@ import org.apache.guacamole.auth.jdbc.user.UserRecordMapper;
 import org.apache.guacamole.auth.jdbc.usergroup.ModeledUserGroup;
 import org.apache.guacamole.auth.jdbc.usergroup.UserGroupDirectory;
 import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMapper;
+import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserMapper;
 import org.apache.guacamole.auth.jdbc.usergroup.UserGroupService;
 import org.mybatis.guice.MyBatisModule;
 import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider;
@@ -136,6 +137,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
         addMapperClass(SharingProfileParameterMapper.class);
         addMapperClass(SharingProfilePermissionMapper.class);
         addMapperClass(UserGroupMapper.class);
+        addMapperClass(UserGroupMemberUserMapper.class);
         addMapperClass(UserGroupPermissionMapper.class);
         addMapperClass(UserMapper.class);
         addMapperClass(UserPermissionMapper.class);

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ccd7920b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
index 470bfab..3612eea 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
@@ -20,6 +20,7 @@
 package org.apache.guacamole.auth.jdbc.usergroup;
 
 import com.google.inject.Inject;
+import com.google.inject.Provider;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -74,10 +75,11 @@ public class ModeledUserGroup extends ModeledPermissions<UserGroupModel>
             )));
 
     /**
-     * Service for managing user groups.
+     * Provider for RelatedObjectSets containing the users that are members of
+     * this user group.
      */
     @Inject
-    private UserGroupService userGroupService;
+    private Provider<UserGroupMemberUserSet> memberUserSetProvider;
 
     /**
      * Whether attributes which control access restrictions should be exposed
@@ -180,7 +182,9 @@ public class ModeledUserGroup extends ModeledPermissions<UserGroupModel>
 
     @Override
     public RelatedObjectSet getMemberUsers() throws GuacamoleException {
-        return new SimpleRelatedObjectSet();
+        UserGroupMemberUserSet memberUserSet = memberUserSetProvider.get();
+        memberUserSet.init(getCurrentUser(), this);
+        return memberUserSet;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ccd7920b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.java
new file mode 100644
index 0000000..b668d07
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.java
@@ -0,0 +1,28 @@
+/*
+ * 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.usergroup;
+
+import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper;
+
+/**
+ * Mapper for the one-to-many relationship between a user group and its user
+ * members.
+ */
+public interface UserGroupMemberUserMapper extends ObjectRelationMapper<UserGroupModel> {}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ccd7920b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserSet.java
new file mode 100644
index 0000000..989df55
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserSet.java
@@ -0,0 +1,57 @@
+/*
+ * 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.usergroup;
+
+import com.google.inject.Inject;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper;
+import org.apache.guacamole.auth.jdbc.base.RelatedObjectSet;
+import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
+
+/**
+ * RelatedObjectSet implementation which represents the one-to-many
+ * relationship between a particular user group and its user members.
+ */
+public class UserGroupMemberUserSet extends RelatedObjectSet<ModeledUserGroup, UserGroupModel> {
+
+    /**
+     * Mapper for the relation between user groups and their user members.
+     */
+    @Inject
+    private UserGroupMemberUserMapper userGroupMemberUserMapper;
+
+    @Override
+    protected ObjectRelationMapper<UserGroupModel> getObjectRelationMapper() {
+        return userGroupMemberUserMapper;
+    }
+
+    @Override
+    protected ObjectPermissionSet
+        getParentObjectEffectivePermissionSet() throws GuacamoleException {
+        return getCurrentUser().getUser().getEffectivePermissions().getUserGroupPermissions();
+    }
+
+    @Override
+    protected ObjectPermissionSet getChildObjectEffectivePermissionSet()
+            throws GuacamoleException {
+        return getCurrentUser().getUser().getEffectivePermissions().getUserPermissions();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ccd7920b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml
new file mode 100644
index 0000000..562b1ad
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserMapper" >
+
+    <!-- Select the username of all member users -->
+    <select id="selectChildIdentifiers" resultType="string">
+        SELECT name
+        FROM guacamole_user_group_member
+        JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group_member.member_entity_id
+        WHERE
+            guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER'::guacamole_entity_type
+    </select>
+
+    <!-- Select the usernames of all readable member users -->
+    <select id="selectReadableChildIdentifiers" resultType="string">
+        SELECT guacamole_entity.name
+        FROM guacamole_user_group_member
+        JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group_member.member_entity_id
+        JOIN guacamole_user ON guacamole_user.entity_id = guacamole_entity.entity_id
+        JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER'::guacamole_entity_type
+            AND permission = 'READ'
+    </select>
+
+    <!-- Delete member users by name -->
+    <delete id="delete">
+        DELETE FROM guacamole_user_group_member
+        USING guacamole_entity
+        WHERE
+            user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            AND guacamole_entity.entity_id = member_entity_id
+            AND guacamole_entity.type = 'USER'::guacamole_entity_type
+            AND guacamole_entity.name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+    </delete>
+
+    <!-- Insert member users by name -->
+    <insert id="insert">
+        INSERT INTO guacamole_user_group_member (
+            user_group_id,
+            member_entity_id
+        )
+        SELECT DISTINCT
+            #{parent.objectID,jdbcType=INTEGER},
+            guacamole_entity.entity_id
+        FROM guacamole_entity
+        WHERE
+            guacamole_entity.name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier}
+                </foreach>
+            AND guacamole_entity.type = 'USER'::guacamole_entity_type
+            AND guacamole_entity.entity_id NOT IN (
+                SELECT guacamole_user_group_member.member_entity_id
+                FROM guacamole_user_group_member
+                WHERE guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            )
+    </insert>
+
+</mapper>


[36/38] guacamole-client git commit: GUACAMOLE-220: Correct typo - "that status of" should be "the status of".

Posted by vn...@apache.org.
GUACAMOLE-220: Correct typo - "that status of" should be "the status of".

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

Branch: refs/heads/master
Commit: 4d5196207bc4bd2381c540a368c8b381e7d8dbce
Parents: f4ccf8e
Author: Michael Jumper <mj...@apache.org>
Authored: Sun Sep 30 23:12:49 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Sun Sep 30 23:12:49 2018 -0700

----------------------------------------------------------------------
 .../java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/4d519620/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java
index a46cb27..f7b75ef 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java
@@ -123,7 +123,7 @@ public abstract class RelatedObjectSet<ParentObjectType extends ModeledDirectory
             throws GuacamoleException;
 
     /**
-     * Returns whether the current user has permission to alter that status of
+     * Returns whether the current user has permission to alter the status of
      * the relation between the parent object and the given child objects.
      *
      * @param identifiers


[13/38] guacamole-client git commit: GUACAMOLE-220: Update MySQL mapping with respect to user group support.

Posted by vn...@apache.org.
http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml
new file mode 100644
index 0000000..37092b4
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.usergroup.UserGroupMapper" >
+
+    <!-- Result mapper for user group objects -->
+    <resultMap id="UserGroupResultMap" type="org.apache.guacamole.auth.jdbc.usergroup.UserGroupModel" >
+
+        <!-- User group properties -->
+        <id     column="user_group_id" property="objectID"   jdbcType="INTEGER"/>
+        <result column="entity_id"     property="entityID"   jdbcType="INTEGER"/>
+        <result column="name"          property="identifier" jdbcType="VARCHAR"/>
+        <result column="disabled"      property="disabled"   jdbcType="BOOLEAN"/>
+
+        <!-- Arbitrary attributes -->
+        <collection property="arbitraryAttributes" resultSet="arbitraryAttributes"
+                    ofType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel"
+                    column="user_group_id" foreignColumn="user_group_id">
+            <result property="name"     column="attribute_name"  jdbcType="VARCHAR"/>
+            <result property="value"    column="attribute_value" jdbcType="VARCHAR"/>
+        </collection>
+
+    </resultMap>
+
+    <!-- Select all group names -->
+    <select id="selectIdentifiers" resultType="string">
+        SELECT name
+        FROM guacamole_entity
+        WHERE guacamole_entity.type = 'USER_GROUP'
+    </select>
+
+    <!-- Select names of all readable groups -->
+    <select id="selectReadableIdentifiers" resultType="string">
+        SELECT guacamole_entity.name
+        FROM guacamole_user_group
+        JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        JOIN guacamole_user_group_permission ON affected_user_group_id = guacamole_user_group.user_group_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_group_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND guacamole_entity.type = 'USER_GROUP'
+            AND permission = 'READ'
+    </select>
+
+    <!-- Select multiple groups by name -->
+    <select id="select" resultMap="UserGroupResultMap"
+            resultSets="users,arbitraryAttributes">
+
+        SELECT
+            guacamole_user_group.user_group_id,
+            guacamole_entity.entity_id,
+            guacamole_entity.name,
+            disabled
+        FROM guacamole_user_group
+        JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        WHERE guacamole_entity.name IN
+            <foreach collection="identifiers" item="identifier"
+                     open="(" separator="," close=")">
+                #{identifier,jdbcType=VARCHAR}
+            </foreach>
+            AND guacamole_entity.type = 'USER_GROUP';
+
+        SELECT
+            guacamole_user_group_attribute.user_group_id,
+            guacamole_user_group_attribute.attribute_name,
+            guacamole_user_group_attribute.attribute_value
+        FROM guacamole_user_group_attribute
+        JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_attribute.user_group_id
+        JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        WHERE guacamole_entity.name IN
+            <foreach collection="identifiers" item="identifier"
+                     open="(" separator="," close=")">
+                #{identifier,jdbcType=VARCHAR}
+            </foreach>
+            AND guacamole_entity.type = 'USER_GROUP';
+
+    </select>
+
+    <!-- Select multiple groups by name only if readable -->
+    <select id="selectReadable" resultMap="UserGroupResultMap"
+            resultSets="users,arbitraryAttributes">
+
+        SELECT
+            guacamole_user_group.user_group_id,
+            guacamole_entity.entity_id,
+            guacamole_entity.name,
+            disabled
+        FROM guacamole_user_group
+        JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        JOIN guacamole_user_group_permission ON affected_user_group_id = guacamole_user_group.user_group_id
+        WHERE guacamole_entity.name IN
+            <foreach collection="identifiers" item="identifier"
+                     open="(" separator="," close=")">
+                #{identifier,jdbcType=VARCHAR}
+            </foreach>
+            AND guacamole_entity.type = 'USER_GROUP'
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_group_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND permission = 'READ';
+
+        SELECT
+            guacamole_user_group_attribute.user_group_id,
+            guacamole_user_group_attribute.attribute_name,
+            guacamole_user_group_attribute.attribute_value
+        FROM guacamole_user_group_attribute
+        JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_attribute.user_group_id
+        JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        JOIN guacamole_user_group_permission ON affected_user_group_id = guacamole_user_group.user_group_id
+        WHERE guacamole_entity.name IN
+            <foreach collection="identifiers" item="identifier"
+                     open="(" separator="," close=")">
+                #{identifier,jdbcType=VARCHAR}
+            </foreach>
+            AND guacamole_entity.type = 'USER_GROUP'
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_group_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND permission = 'READ';
+
+    </select>
+
+    <!-- Select single group by name -->
+    <select id="selectOne" resultMap="UserGroupResultMap"
+            resultSets="users,arbitraryAttributes">
+
+        SELECT
+            guacamole_user_group.user_group_id,
+            guacamole_entity.entity_id,
+            guacamole_entity.name,
+            disabled
+        FROM guacamole_user_group
+        JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        WHERE
+            guacamole_entity.name = #{name,jdbcType=VARCHAR}
+            AND guacamole_entity.type = 'USER_GROUP';
+
+        SELECT
+            guacamole_user_group_attribute.user_group_id,
+            guacamole_user_group_attribute.attribute_name,
+            guacamole_user_group_attribute.attribute_value
+        FROM guacamole_user_group_attribute
+        JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_attribute.user_group_id
+        JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        WHERE
+            guacamole_entity.name = #{name,jdbcType=VARCHAR}
+            AND guacamole_entity.type = 'USER_GROUP'
+
+    </select>
+
+    <!-- Delete single group by name -->
+    <delete id="delete">
+        DELETE FROM guacamole_entity
+        WHERE
+            name = #{identifier,jdbcType=VARCHAR}
+            AND type = 'USER_GROUP'
+    </delete>
+
+    <!-- Insert single group -->
+    <insert id="insert" useGeneratedKeys="true" keyProperty="object.objectID"
+            parameterType="org.apache.guacamole.auth.jdbc.usergroup.UserGroupModel">
+
+        INSERT INTO guacamole_user_group (
+            entity_id,
+            disabled
+        )
+        VALUES (
+            #{object.entityID,jdbcType=VARCHAR},
+            #{object.disabled,jdbcType=BOOLEAN}
+        )
+
+    </insert>
+
+    <!-- Update single group -->
+    <update id="update" parameterType="org.apache.guacamole.auth.jdbc.usergroup.UserGroupModel">
+        UPDATE guacamole_user_group
+        SET disabled = #{object.disabled,jdbcType=BOOLEAN}
+        WHERE user_group_id = #{object.objectID,jdbcType=VARCHAR}
+    </update>
+
+    <!-- Delete attributes associated with group -->
+    <delete id="deleteAttributes">
+        DELETE FROM guacamole_user_group_attribute
+        WHERE user_group_id = #{object.objectID,jdbcType=INTEGER}
+    </delete>
+
+    <!-- Insert attributes for group -->
+    <insert id="insertAttributes" parameterType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel">
+        INSERT INTO guacamole_user_group_attribute (
+            user_group_id,
+            attribute_name,
+            attribute_value
+        )
+        VALUES
+            <foreach collection="object.arbitraryAttributes" item="attribute" separator=",">
+                (#{object.objectID,jdbcType=INTEGER},
+                 #{attribute.name,jdbcType=VARCHAR},
+                 #{attribute.value,jdbcType=VARCHAR})
+            </foreach>
+    </insert>
+
+</mapper>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml
new file mode 100644
index 0000000..aedc956
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserGroupMapper" >
+
+    <!-- Select the names of all member user groups -->
+    <select id="selectChildIdentifiers" resultType="string">
+        SELECT name
+        FROM guacamole_user_group_member
+        JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group_member.member_entity_id
+        WHERE
+            guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER_GROUP'
+    </select>
+
+    <!-- Select the names of all readable member user groups -->
+    <select id="selectReadableChildIdentifiers" resultType="string">
+        SELECT guacamole_entity.name
+        FROM guacamole_user_group_member
+        JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group_member.member_entity_id
+        JOIN guacamole_user_group ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        JOIN guacamole_user_group_permission ON affected_user_group_id = guacamole_user_group.user_group_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_group_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER_GROUP'
+            AND permission = 'READ'
+    </select>
+
+    <!-- Delete member groups by name -->
+    <delete id="delete">
+        DELETE FROM guacamole_user_group_member
+        USING guacamole_user_group_member
+        JOIN guacamole_entity ON guacamole_entity.entity_id = member_entity_id
+        WHERE
+            user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER_GROUP'
+            AND guacamole_entity.name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+    </delete>
+
+    <!-- Insert member groups by name -->
+    <insert id="insert">
+        INSERT INTO guacamole_user_group_member (
+            user_group_id,
+            member_entity_id
+        )
+        SELECT DISTINCT
+            #{parent.objectID,jdbcType=INTEGER},
+            guacamole_entity.entity_id
+        FROM guacamole_entity
+        WHERE
+            guacamole_entity.name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier}
+                </foreach>
+            AND guacamole_entity.type = 'USER_GROUP'
+            AND guacamole_entity.entity_id NOT IN (
+                SELECT guacamole_user_group_member.member_entity_id
+                FROM guacamole_user_group_member
+                WHERE guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            )
+    </insert>
+
+</mapper>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml
new file mode 100644
index 0000000..9e08203
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserMapper" >
+
+    <!-- Select the username of all member users -->
+    <select id="selectChildIdentifiers" resultType="string">
+        SELECT name
+        FROM guacamole_user_group_member
+        JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group_member.member_entity_id
+        WHERE
+            guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER'
+    </select>
+
+    <!-- Select the usernames of all readable member users -->
+    <select id="selectReadableChildIdentifiers" resultType="string">
+        SELECT guacamole_entity.name
+        FROM guacamole_user_group_member
+        JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group_member.member_entity_id
+        JOIN guacamole_user ON guacamole_user.entity_id = guacamole_entity.entity_id
+        JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER'
+            AND permission = 'READ'
+    </select>
+
+    <!-- Delete member users by name -->
+    <delete id="delete">
+        DELETE FROM guacamole_user_group_member
+        USING guacamole_user_group_member
+        JOIN guacamole_entity ON guacamole_entity.entity_id = member_entity_id
+        WHERE
+            user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER'
+            AND guacamole_entity.name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+    </delete>
+
+    <!-- Insert member users by name -->
+    <insert id="insert">
+        INSERT INTO guacamole_user_group_member (
+            user_group_id,
+            member_entity_id
+        )
+        SELECT DISTINCT
+            #{parent.objectID,jdbcType=INTEGER},
+            guacamole_entity.entity_id
+        FROM guacamole_entity
+        WHERE
+            guacamole_entity.name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier}
+                </foreach>
+            AND guacamole_entity.type = 'USER'
+            AND guacamole_entity.entity_id NOT IN (
+                SELECT guacamole_user_group_member.member_entity_id
+                FROM guacamole_user_group_member
+                WHERE guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            )
+    </insert>
+
+</mapper>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml
new file mode 100644
index 0000000..4ef3c72
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.usergroup.UserGroupParentUserGroupMapper" >
+
+    <!-- Select the names of all parent user groups -->
+    <select id="selectChildIdentifiers" resultType="string">
+        SELECT name
+        FROM guacamole_user_group_member
+        JOIN guacamole_user_group ON guacamole_user_group_member.user_group_id = guacamole_user_group.user_group_id
+        JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group.entity_id
+        WHERE
+            guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER_GROUP'
+    </select>
+
+    <!-- Select the names of all readable parent user groups -->
+    <select id="selectReadableChildIdentifiers" resultType="string">
+        SELECT guacamole_entity.name
+        FROM guacamole_user_group_member
+        JOIN guacamole_user_group ON guacamole_user_group_member.user_group_id = guacamole_user_group.user_group_id
+        JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group.entity_id
+        JOIN guacamole_user_group_permission ON affected_user_group_id = guacamole_user_group.user_group_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_group_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER_GROUP'
+            AND permission = 'READ'
+    </select>
+
+    <!-- Delete parent groups by name -->
+    <delete id="delete">
+        DELETE FROM guacamole_user_group_member
+        USING guacamole_user_group_member
+        JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
+        JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group.entity_id
+        WHERE
+            member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER_GROUP'
+            AND guacamole_entity.name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+    </delete>
+
+    <!-- Insert parent groups by name -->
+    <insert id="insert">
+        INSERT INTO guacamole_user_group_member (
+            user_group_id,
+            member_entity_id
+        )
+        SELECT DISTINCT
+            guacamole_user_group.user_group_id,
+            #{parent.entityID,jdbcType=INTEGER}
+        FROM guacamole_user_group
+        JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        WHERE
+            guacamole_entity.name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+            AND guacamole_entity.type = 'USER_GROUP'
+            AND guacamole_user_group.user_group_id NOT IN (
+                SELECT guacamole_user_group_member.user_group_id
+                FROM guacamole_user_group_member
+                WHERE guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            )
+    </insert>
+
+</mapper>


[12/38] guacamole-client git commit: GUACAMOLE-220: Define base schema for user groups.

Posted by vn...@apache.org.
GUACAMOLE-220: Define base schema for user groups.


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

Branch: refs/heads/master
Commit: e72f88febff5766345fa4a8f9086639ea997a2e9
Parents: d23f88f
Author: Michael Jumper <mj...@apache.org>
Authored: Fri Mar 2 14:45:33 2018 -0800
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:51 2018 -0700

----------------------------------------------------------------------
 .../schema/001-create-schema.sql                | 233 +++++++++---
 .../schema/002-create-admin-user.sql            |  27 +-
 .../schema/upgrade/upgrade-pre-1.0.0.sql        | 357 +++++++++++++++++++
 3 files changed, 558 insertions(+), 59 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/e72f88fe/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql
index ddd3566..9bcf1c5 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql
@@ -27,6 +27,15 @@ CREATE TYPE guacamole_connection_group_type AS ENUM(
 );
 
 --
+-- Entity types
+--
+
+CREATE TYPE guacamole_entity_type AS ENUM(
+    'USER',
+    'USER_GROUP'
+);
+
+--
 -- Object permission types
 --
 
@@ -46,6 +55,7 @@ CREATE TYPE guacamole_system_permission_type AS ENUM(
     'CREATE_CONNECTION_GROUP',
     'CREATE_SHARING_PROFILE',
     'CREATE_USER',
+    'CREATE_USER_GROUP',
     'ADMINISTER'
 );
 
@@ -132,6 +142,26 @@ CREATE INDEX guacamole_connection_parent_id
     ON guacamole_connection(parent_id);
 
 --
+-- Table of base entities which may each be either a user or user group. Other
+-- tables which represent qualities shared by both users and groups will point
+-- to guacamole_entity, while tables which represent qualities specific to
+-- users or groups will point to guacamole_user or guacamole_user_group.
+--
+
+CREATE TABLE guacamole_entity (
+
+  entity_id     serial                  NOT NULL,
+  name          varchar(128)            NOT NULL,
+  type          guacamole_entity_type   NOT NULL,
+
+  PRIMARY KEY (entity_id),
+
+  CONSTRAINT guacamole_entity_name_scope
+    UNIQUE (type, name)
+
+);
+
+--
 -- Table of users. Each user has a unique username and a hashed password
 -- with corresponding salt. Although the authentication system will always set
 -- salted passwords, other systems may set unsalted passwords by simply not
@@ -141,9 +171,9 @@ CREATE INDEX guacamole_connection_parent_id
 CREATE TABLE guacamole_user (
 
   user_id       serial       NOT NULL,
+  entity_id     integer      NOT NULL,
 
-  -- Username and optionally-salted password
-  username      varchar(128) NOT NULL,
+  -- Optionally-salted password
   password_hash bytea        NOT NULL,
   password_salt bytea,
   password_date timestamptz  NOT NULL,
@@ -171,8 +201,62 @@ CREATE TABLE guacamole_user (
 
   PRIMARY KEY (user_id),
 
-  CONSTRAINT username
-    UNIQUE (username)
+  CONSTRAINT guacamole_user_single_entity
+    UNIQUE (entity_id),
+
+  CONSTRAINT guacamole_user_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id)
+    ON DELETE CASCADE
+
+);
+
+--
+-- Table of user groups. Each user group may have an arbitrary set of member
+-- users and member groups, with those members inheriting the permissions
+-- granted to that group.
+--
+
+CREATE TABLE guacamole_user_group (
+
+  user_group_id serial      NOT NULL,
+  entity_id     integer     NOT NULL,
+
+  -- Group disabled status
+  disabled      boolean     NOT NULL DEFAULT FALSE,
+
+  PRIMARY KEY (user_group_id),
+
+  CONSTRAINT guacamole_user_group_single_entity
+    UNIQUE (entity_id),
+
+  CONSTRAINT guacamole_user_group_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id)
+    ON DELETE CASCADE
+
+);
+
+--
+-- Table of users which are members of given user groups.
+--
+
+CREATE TABLE guacamole_user_group_member (
+
+  user_group_id    integer       NOT NULL,
+  member_entity_id integer       NOT NULL,
+
+  PRIMARY KEY (user_group_id, member_entity_id),
+
+  -- Parent must be a user group
+  CONSTRAINT guacamole_user_group_member_parent
+    FOREIGN KEY (user_group_id)
+    REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE,
+
+  -- Member may be either a user or a user group (any entity)
+  CONSTRAINT guacamole_user_group_member_entity
+    FOREIGN KEY (member_entity_id)
+    REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
 
 );
 
@@ -276,6 +360,30 @@ CREATE INDEX guacamole_user_attribute_user_id
     ON guacamole_user_attribute(user_id);
 
 --
+-- Table of arbitrary user group attributes. Each attribute is simply a
+-- name/value pair associated with a user group. Arbitrary attributes are
+-- defined by other extensions. Attributes defined by this extension will be
+-- mapped to properly-typed columns of a specific table.
+--
+
+CREATE TABLE guacamole_user_group_attribute (
+
+  user_group_id   integer       NOT NULL,
+  attribute_name  varchar(128)  NOT NULL,
+  attribute_value varchar(4096) NOT NULL,
+
+  PRIMARY KEY (user_group_id, attribute_name),
+
+  CONSTRAINT guacamole_user_group_attribute_ibfk_1
+    FOREIGN KEY (user_group_id)
+    REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE
+
+);
+
+CREATE INDEX guacamole_user_group_attribute_user_group_id
+    ON guacamole_user_group_attribute(user_group_id);
+
+--
 -- Table of arbitrary connection attributes. Each attribute is simply a
 -- name/value pair associated with a connection. Arbitrary attributes are
 -- defined by other extensions. Attributes defined by this extension will be
@@ -348,141 +456,172 @@ CREATE INDEX guacamole_sharing_profile_attribute_sharing_profile_id
     ON guacamole_sharing_profile_attribute(sharing_profile_id);
 
 --
--- Table of connection permissions. Each connection permission grants a user
--- specific access to a connection.
+-- Table of connection permissions. Each connection permission grants a user or
+-- user group specific access to a connection.
 --
 
 CREATE TABLE guacamole_connection_permission (
 
-  user_id       integer NOT NULL,
+  entity_id     integer NOT NULL,
   connection_id integer NOT NULL,
   permission    guacamole_object_permission_type NOT NULL,
 
-  PRIMARY KEY (user_id,connection_id,permission),
+  PRIMARY KEY (entity_id, connection_id, permission),
 
   CONSTRAINT guacamole_connection_permission_ibfk_1
     FOREIGN KEY (connection_id)
     REFERENCES guacamole_connection (connection_id) ON DELETE CASCADE,
 
-  CONSTRAINT guacamole_connection_permission_ibfk_2
-    FOREIGN KEY (user_id)
-    REFERENCES guacamole_user (user_id) ON DELETE CASCADE
+  CONSTRAINT guacamole_connection_permission_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
 
 );
 
 CREATE INDEX guacamole_connection_permission_connection_id
     ON guacamole_connection_permission(connection_id);
 
-CREATE INDEX guacamole_connection_permission_user_id
-    ON guacamole_connection_permission(user_id);
+CREATE INDEX guacamole_connection_permission_entity_id
+    ON guacamole_connection_permission(entity_id);
 
 --
 -- Table of connection group permissions. Each group permission grants a user
--- specific access to a connection group.
+-- or user group specific access to a connection group.
 --
 
 CREATE TABLE guacamole_connection_group_permission (
 
-  user_id             integer NOT NULL,
+  entity_id           integer NOT NULL,
   connection_group_id integer NOT NULL,
   permission          guacamole_object_permission_type NOT NULL,
 
-  PRIMARY KEY (user_id,connection_group_id,permission),
+  PRIMARY KEY (entity_id, connection_group_id, permission),
 
   CONSTRAINT guacamole_connection_group_permission_ibfk_1
     FOREIGN KEY (connection_group_id)
     REFERENCES guacamole_connection_group (connection_group_id) ON DELETE CASCADE,
 
-  CONSTRAINT guacamole_connection_group_permission_ibfk_2
-    FOREIGN KEY (user_id)
-    REFERENCES guacamole_user (user_id) ON DELETE CASCADE
+  CONSTRAINT guacamole_connection_group_permission_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
 
 );
 
 CREATE INDEX guacamole_connection_group_permission_connection_group_id
     ON guacamole_connection_group_permission(connection_group_id);
 
-CREATE INDEX guacamole_connection_group_permission_user_id
-    ON guacamole_connection_group_permission(user_id);
+CREATE INDEX guacamole_connection_group_permission_entity_id
+    ON guacamole_connection_group_permission(entity_id);
 
 --
 -- Table of sharing profile permissions. Each sharing profile permission grants
--- a user specific access to a sharing profile.
+-- a user or user group specific access to a sharing profile.
 --
 
 CREATE TABLE guacamole_sharing_profile_permission (
 
-  user_id            integer NOT NULL,
+  entity_id          integer NOT NULL,
   sharing_profile_id integer NOT NULL,
   permission         guacamole_object_permission_type NOT NULL,
 
-  PRIMARY KEY (user_id,sharing_profile_id,permission),
+  PRIMARY KEY (entity_id, sharing_profile_id, permission),
 
   CONSTRAINT guacamole_sharing_profile_permission_ibfk_1
     FOREIGN KEY (sharing_profile_id)
     REFERENCES guacamole_sharing_profile (sharing_profile_id) ON DELETE CASCADE,
 
-  CONSTRAINT guacamole_sharing_profile_permission_ibfk_2
-    FOREIGN KEY (user_id)
-    REFERENCES guacamole_user (user_id) ON DELETE CASCADE
+  CONSTRAINT guacamole_sharing_profile_permission_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
 
 );
 
 CREATE INDEX guacamole_sharing_profile_permission_sharing_profile_id
     ON guacamole_sharing_profile_permission(sharing_profile_id);
 
-CREATE INDEX guacamole_sharing_profile_permission_user_id
-    ON guacamole_sharing_profile_permission(user_id);
+CREATE INDEX guacamole_sharing_profile_permission_entity_id
+    ON guacamole_sharing_profile_permission(entity_id);
 
 --
--- Table of system permissions. Each system permission grants a user a
--- system-level privilege of some kind.
+-- Table of system permissions. Each system permission grants a user or user
+-- group a system-level privilege of some kind.
 --
 
 CREATE TABLE guacamole_system_permission (
 
-  user_id    integer NOT NULL,
+  entity_id  integer NOT NULL,
   permission guacamole_system_permission_type NOT NULL,
 
-  PRIMARY KEY (user_id,permission),
+  PRIMARY KEY (entity_id, permission),
 
-  CONSTRAINT guacamole_system_permission_ibfk_1
-    FOREIGN KEY (user_id)
-    REFERENCES guacamole_user (user_id) ON DELETE CASCADE
+  CONSTRAINT guacamole_system_permission_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
 
 );
 
-CREATE INDEX guacamole_system_permission_user_id
-    ON guacamole_system_permission(user_id);
+CREATE INDEX guacamole_system_permission_entity_id
+    ON guacamole_system_permission(entity_id);
 
 --
--- Table of user permissions. Each user permission grants a user access to
--- another user (the "affected" user) for a specific type of operation.
+-- Table of user permissions. Each user permission grants a user or user group
+-- access to another user (the "affected" user) for a specific type of
+-- operation.
 --
 
 CREATE TABLE guacamole_user_permission (
 
-  user_id          integer NOT NULL,
+  entity_id        integer NOT NULL,
   affected_user_id integer NOT NULL,
   permission       guacamole_object_permission_type NOT NULL,
 
-  PRIMARY KEY (user_id,affected_user_id,permission),
+  PRIMARY KEY (entity_id, affected_user_id, permission),
 
   CONSTRAINT guacamole_user_permission_ibfk_1
     FOREIGN KEY (affected_user_id)
     REFERENCES guacamole_user (user_id) ON DELETE CASCADE,
 
-  CONSTRAINT guacamole_user_permission_ibfk_2
-    FOREIGN KEY (user_id)
-    REFERENCES guacamole_user (user_id) ON DELETE CASCADE
+  CONSTRAINT guacamole_user_permission_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
 
 );
 
 CREATE INDEX guacamole_user_permission_affected_user_id
     ON guacamole_user_permission(affected_user_id);
 
-CREATE INDEX guacamole_user_permission_user_id
-    ON guacamole_user_permission(user_id);
+CREATE INDEX guacamole_user_permission_entity_id
+    ON guacamole_user_permission(entity_id);
+
+--
+-- Table of user group permissions. Each user group permission grants a user
+-- or user group access to a another user group (the "affected" user group) for
+-- a specific type of operation.
+--
+
+CREATE TABLE guacamole_user_group_permission (
+
+  entity_id              integer NOT NULL,
+  affected_user_group_id integer NOT NULL,
+  permission             guacamole_object_permission_type NOT NULL,
+
+  PRIMARY KEY (entity_id, affected_user_group_id, permission),
+
+  CONSTRAINT guacamole_user_group_permission_affected_user_group
+    FOREIGN KEY (affected_user_group_id)
+    REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE,
+
+  CONSTRAINT guacamole_user_group_permission_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
+
+);
+
+CREATE INDEX guacamole_user_group_permission_affected_user_group_id
+    ON guacamole_user_group_permission(affected_user_group_id);
+
+CREATE INDEX guacamole_user_group_permission_entity_id
+    ON guacamole_user_group_permission(entity_id);
 
 --
 -- Table of connection history records. Each record defines a specific user's

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/e72f88fe/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql
index 47eebd2..c7cd7c9 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql
@@ -17,36 +17,39 @@
 -- under the License.
 --
 
-
 -- Create default user "guacadmin" with password "guacadmin"
-INSERT INTO guacamole_user (username, password_hash, password_salt, password_date)
-VALUES ('guacadmin',
+INSERT INTO guacamole_entity (name, type) VALUES ('guacadmin', 'USER');
+INSERT INTO guacamole_user (entity_id, password_hash, password_salt, password_date)
+SELECT
+    entity_id,
     decode('CA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960', 'hex'),  -- 'guacadmin'
     decode('FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264', 'hex'),
-    CURRENT_TIMESTAMP);
+    CURRENT_TIMESTAMP
+FROM guacamole_entity WHERE name = 'guacadmin' AND guacamole_entity.type = 'USER';
 
 -- Grant this user all system permissions
-INSERT INTO guacamole_system_permission
-SELECT user_id, permission::guacamole_system_permission_type
+INSERT INTO guacamole_system_permission (entity_id, permission)
+SELECT entity_id, permission::guacamole_system_permission_type
 FROM (
     VALUES
         ('guacadmin', 'CREATE_CONNECTION'),
         ('guacadmin', 'CREATE_CONNECTION_GROUP'),
         ('guacadmin', 'CREATE_SHARING_PROFILE'),
         ('guacadmin', 'CREATE_USER'),
+        ('guacadmin', 'CREATE_USER_GROUP'),
         ('guacadmin', 'ADMINISTER')
 ) permissions (username, permission)
-JOIN guacamole_user ON permissions.username = guacamole_user.username;
+JOIN guacamole_entity ON permissions.username = guacamole_entity.name AND guacamole_entity.type = 'USER';
 
 -- Grant admin permission to read/update/administer self
-INSERT INTO guacamole_user_permission
-SELECT guacamole_user.user_id, affected.user_id, permission::guacamole_object_permission_type
+INSERT INTO guacamole_user_permission (entity_id, affected_user_id, permission)
+SELECT guacamole_entity.entity_id, guacamole_user.user_id, permission::guacamole_object_permission_type
 FROM (
     VALUES
         ('guacadmin', 'guacadmin', 'READ'),
         ('guacadmin', 'guacadmin', 'UPDATE'),
         ('guacadmin', 'guacadmin', 'ADMINISTER')
 ) permissions (username, affected_username, permission)
-JOIN guacamole_user          ON permissions.username = guacamole_user.username
-JOIN guacamole_user affected ON permissions.affected_username = affected.username;
-
+JOIN guacamole_entity          ON permissions.username = guacamole_entity.name AND guacamole_entity.type = 'USER'
+JOIN guacamole_entity affected ON permissions.affected_username = affected.name AND guacamole_entity.type = 'USER'
+JOIN guacamole_user            ON guacamole_user.entity_id = affected.entity_id;

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/e72f88fe/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.0.0.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.0.0.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.0.0.sql
index db115c2..dd341dc 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.0.0.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.0.0.sql
@@ -18,6 +18,339 @@
 --
 
 --
+-- Add new system-level permission
+--
+
+ALTER TYPE guacamole_system_permission_type
+    ADD VALUE 'CREATE_USER_GROUP'
+    AFTER 'CREATE_USER';
+
+--
+-- Entity types
+--
+
+CREATE TYPE guacamole_entity_type AS ENUM(
+    'USER',
+    'USER_GROUP'
+);
+
+--
+-- Table of base entities which may each be either a user or user group. Other
+-- tables which represent qualities shared by both users and groups will point
+-- to guacamole_entity, while tables which represent qualities specific to
+-- users or groups will point to guacamole_user or guacamole_user_group.
+--
+
+CREATE TABLE guacamole_entity (
+
+  entity_id     serial                  NOT NULL,
+  name          varchar(128)            NOT NULL,
+  type          guacamole_entity_type   NOT NULL,
+
+  PRIMARY KEY (entity_id),
+
+  CONSTRAINT guacamole_entity_name_scope
+    UNIQUE (type, name)
+
+);
+
+--
+-- Table of user groups. Each user group may have an arbitrary set of member
+-- users and member groups, with those members inheriting the permissions
+-- granted to that group.
+--
+
+CREATE TABLE guacamole_user_group (
+
+  user_group_id serial      NOT NULL,
+  entity_id     integer     NOT NULL,
+
+  -- Group disabled status
+  disabled      boolean     NOT NULL DEFAULT FALSE,
+
+  PRIMARY KEY (user_group_id),
+
+  CONSTRAINT guacamole_user_group_single_entity
+    UNIQUE (entity_id),
+
+  CONSTRAINT guacamole_user_group_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id)
+    ON DELETE CASCADE
+
+);
+
+--
+-- Table of users which are members of given user groups.
+--
+
+CREATE TABLE guacamole_user_group_member (
+
+  user_group_id    integer       NOT NULL,
+  member_entity_id integer       NOT NULL,
+
+  PRIMARY KEY (user_group_id, member_entity_id),
+
+  -- Parent must be a user group
+  CONSTRAINT guacamole_user_group_member_parent
+    FOREIGN KEY (user_group_id)
+    REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE,
+
+  -- Member may be either a user or a user group (any entity)
+  CONSTRAINT guacamole_user_group_member_entity
+    FOREIGN KEY (member_entity_id)
+    REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
+
+);
+
+--
+-- Table of user group permissions. Each user group permission grants a user
+-- access to a particular user group for a specific type of operation.
+--
+
+CREATE TABLE guacamole_user_group_permission (
+
+  entity_id              integer NOT NULL,
+  affected_user_group_id integer NOT NULL,
+  permission             guacamole_object_permission_type NOT NULL,
+
+  PRIMARY KEY (entity_id, affected_user_group_id, permission),
+
+  CONSTRAINT guacamole_user_group_permission_affected_user_group
+    FOREIGN KEY (affected_user_group_id)
+    REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE,
+
+  CONSTRAINT guacamole_user_group_permission_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id) ON DELETE CASCADE
+
+);
+
+CREATE INDEX guacamole_user_group_permission_affected_user_group_id
+    ON guacamole_user_group_permission(affected_user_group_id);
+
+CREATE INDEX guacamole_user_group_permission_entity_id
+    ON guacamole_user_group_permission(entity_id);
+
+--
+-- Modify guacamole_user table to use guacamole_entity as a base
+--
+
+-- Add new entity_id column
+ALTER TABLE guacamole_user ADD COLUMN entity_id integer;
+
+-- Create user entities for each guacamole_user entry
+INSERT INTO guacamole_entity (name, type)
+SELECT username, 'USER' FROM guacamole_user;
+
+-- Update guacamole_user to point to corresponding guacamole_entity
+UPDATE guacamole_user SET entity_id = (
+    SELECT entity_id FROM guacamole_entity
+    WHERE
+            username = guacamole_entity.name
+        AND type = 'USER'
+);
+
+-- The entity_id column should now be safely non-NULL
+ALTER TABLE guacamole_user
+    ALTER COLUMN entity_id SET NOT NULL;
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE guacamole_user
+    ADD CONSTRAINT guacamole_user_single_entity
+    UNIQUE (entity_id);
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE guacamole_user
+    ADD CONSTRAINT guacamole_user_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id)
+    ON DELETE CASCADE;
+
+-- The username column can now safely be removed
+ALTER TABLE guacamole_user DROP COLUMN username;
+
+--
+-- Modify guacamole_connection_permission to use guacamole_entity instead of
+-- guacamole_user
+--
+
+-- Add new entity_id column
+ALTER TABLE guacamole_connection_permission ADD COLUMN entity_id integer;
+
+-- Update guacamole_connection_permission to point to the guacamole_entity
+-- that has been granted the permission
+UPDATE guacamole_connection_permission SET entity_id = (
+    SELECT entity_id FROM guacamole_user
+    WHERE guacamole_user.user_id = guacamole_connection_permission.user_id
+);
+
+-- The entity_id column should now be safely non-NULL
+ALTER TABLE guacamole_connection_permission
+    ALTER COLUMN entity_id SET NOT NULL;
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE guacamole_connection_permission
+    ADD CONSTRAINT guacamole_connection_permission_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id)
+    ON DELETE CASCADE;
+
+CREATE INDEX guacamole_connection_permission_entity_id
+    ON guacamole_connection_permission(entity_id);
+
+-- Remove user_id column (implicitly drops associated contraints/keys)
+ALTER TABLE guacamole_connection_permission DROP COLUMN user_id;
+
+-- Add new primary key which uses entity_id
+ALTER TABLE guacamole_connection_permission
+    ADD PRIMARY KEY (entity_id, connection_id, permission);
+
+--
+-- Modify guacamole_connection_group_permission to use guacamole_entity instead
+-- of guacamole_user
+--
+
+-- Add new entity_id column
+ALTER TABLE guacamole_connection_group_permission ADD COLUMN entity_id integer;
+
+-- Update guacamole_connection_group_permission to point to the guacamole_entity
+-- that has been granted the permission
+UPDATE guacamole_connection_group_permission SET entity_id = (
+    SELECT entity_id FROM guacamole_user
+    WHERE guacamole_user.user_id = guacamole_connection_group_permission.user_id
+);
+
+-- The entity_id column should now be safely non-NULL
+ALTER TABLE guacamole_connection_group_permission
+    ALTER COLUMN entity_id SET NOT NULL;
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE guacamole_connection_group_permission
+    ADD CONSTRAINT guacamole_connection_group_permission_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id)
+    ON DELETE CASCADE;
+
+CREATE INDEX guacamole_connection_group_permission_entity_id
+    ON guacamole_connection_group_permission(entity_id);
+
+-- Remove user_id column (implicitly drops associated contraints/keys)
+ALTER TABLE guacamole_connection_group_permission DROP COLUMN user_id;
+
+-- Add new primary key which uses entity_id
+ALTER TABLE guacamole_connection_group_permission
+    ADD PRIMARY KEY (entity_id, connection_group_id, permission);
+
+--
+-- Modify guacamole_sharing_profile_permission to use guacamole_entity instead
+-- of guacamole_user
+--
+
+-- Add new entity_id column
+ALTER TABLE guacamole_sharing_profile_permission ADD COLUMN entity_id integer;
+
+-- Update guacamole_sharing_profile_permission to point to the guacamole_entity
+-- that has been granted the permission
+UPDATE guacamole_sharing_profile_permission SET entity_id = (
+    SELECT entity_id FROM guacamole_user
+    WHERE guacamole_user.user_id = guacamole_sharing_profile_permission.user_id
+);
+
+-- The entity_id column should now be safely non-NULL
+ALTER TABLE guacamole_sharing_profile_permission
+    ALTER COLUMN entity_id SET NOT NULL;
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE guacamole_sharing_profile_permission
+    ADD CONSTRAINT guacamole_sharing_profile_permission_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id)
+    ON DELETE CASCADE;
+
+CREATE INDEX guacamole_sharing_profile_permission_entity_id
+    ON guacamole_sharing_profile_permission(entity_id);
+
+-- Remove user_id column (implicitly drops associated contraints/keys)
+ALTER TABLE guacamole_sharing_profile_permission DROP COLUMN user_id;
+
+-- Add new primary key which uses entity_id
+ALTER TABLE guacamole_sharing_profile_permission
+    ADD PRIMARY KEY (entity_id, sharing_profile_id, permission);
+
+--
+-- Modify guacamole_user_permission to use guacamole_entity instead of
+-- guacamole_user
+--
+
+-- Add new entity_id column
+ALTER TABLE guacamole_user_permission ADD COLUMN entity_id integer;
+
+-- Update guacamole_user_permission to point to the guacamole_entity
+-- that has been granted the permission
+UPDATE guacamole_user_permission SET entity_id = (
+    SELECT entity_id FROM guacamole_user
+    WHERE guacamole_user.user_id = guacamole_user_permission.user_id
+);
+
+-- The entity_id column should now be safely non-NULL
+ALTER TABLE guacamole_user_permission
+    ALTER COLUMN entity_id SET NOT NULL;
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE guacamole_user_permission
+    ADD CONSTRAINT guacamole_user_permission_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id)
+    ON DELETE CASCADE;
+
+CREATE INDEX guacamole_user_permission_entity_id
+    ON guacamole_user_permission(entity_id);
+
+-- Remove user_id column (implicitly drops associated contraints/keys)
+ALTER TABLE guacamole_user_permission DROP COLUMN user_id;
+
+-- Add new primary key which uses entity_id
+ALTER TABLE guacamole_user_permission
+    ADD PRIMARY KEY (entity_id, affected_user_id, permission);
+
+--
+-- Modify guacamole_system_permission to use guacamole_entity instead of
+-- guacamole_user
+--
+
+-- Add new entity_id column
+ALTER TABLE guacamole_system_permission ADD COLUMN entity_id integer;
+
+-- Update guacamole_system_permission to point to the guacamole_entity
+-- that has been granted the permission
+UPDATE guacamole_system_permission SET entity_id = (
+    SELECT entity_id FROM guacamole_user
+    WHERE guacamole_user.user_id = guacamole_system_permission.user_id
+);
+
+-- The entity_id column should now be safely non-NULL
+ALTER TABLE guacamole_system_permission
+    ALTER COLUMN entity_id SET NOT NULL;
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE guacamole_system_permission
+    ADD CONSTRAINT guacamole_system_permission_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id)
+    ON DELETE CASCADE;
+
+CREATE INDEX guacamole_system_permission_entity_id
+    ON guacamole_system_permission(entity_id);
+
+-- Remove user_id column (implicitly drops associated contraints/keys)
+ALTER TABLE guacamole_system_permission DROP COLUMN user_id;
+
+-- Add new primary key which uses entity_id
+ALTER TABLE guacamole_system_permission
+    ADD PRIMARY KEY (entity_id, permission);
+
+--
 -- Table of arbitrary user attributes. Each attribute is simply a name/value
 -- pair associated with a user. Arbitrary attributes are defined by other
 -- extensions. Attributes defined by this extension will be mapped to
@@ -42,6 +375,30 @@ CREATE INDEX guacamole_user_attribute_user_id
     ON guacamole_user_attribute(user_id);
 
 --
+-- Table of arbitrary user group attributes. Each attribute is simply a
+-- name/value pair associated with a user group. Arbitrary attributes are
+-- defined by other extensions. Attributes defined by this extension will be
+-- mapped to properly-typed columns of a specific table.
+--
+
+CREATE TABLE guacamole_user_group_attribute (
+
+  user_group_id   integer       NOT NULL,
+  attribute_name  varchar(128)  NOT NULL,
+  attribute_value varchar(4096) NOT NULL,
+
+  PRIMARY KEY (user_group_id, attribute_name),
+
+  CONSTRAINT guacamole_user_group_attribute_ibfk_1
+    FOREIGN KEY (user_group_id)
+    REFERENCES guacamole_user_group (user_group_id) ON DELETE CASCADE
+
+);
+
+CREATE INDEX guacamole_user_group_attribute_user_group_id
+    ON guacamole_user_group_attribute(user_group_id);
+
+--
 -- Table of arbitrary connection attributes. Each attribute is simply a
 -- name/value pair associated with a connection. Arbitrary attributes are
 -- defined by other extensions. Attributes defined by this extension will be


[06/38] guacamole-client git commit: GUACAMOLE-220: Implement base API changes within database auth allowing for permission inheritance.

Posted by vn...@apache.org.
GUACAMOLE-220: Implement base API changes within database auth allowing for permission inheritance.


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

Branch: refs/heads/master
Commit: 0a69630cbb0f80cd819136dce4127dfa6366e1a2
Parents: 72bac09
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Apr 3 21:32:38 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:51 2018 -0700

----------------------------------------------------------------------
 .../ActiveConnectionPermissionService.java      | 26 ++++-----
 .../ConnectionGroupPermissionService.java       |  4 +-
 .../permission/ConnectionPermissionService.java |  4 +-
 .../ModeledObjectPermissionService.java         | 23 +++-----
 .../permission/ModeledPermissionService.java    | 12 ++--
 .../jdbc/permission/ObjectPermissionMapper.java | 20 +++++--
 .../permission/ObjectPermissionService.java     | 27 ++++++---
 .../jdbc/permission/ObjectPermissionSet.java    | 23 ++++++--
 .../auth/jdbc/permission/PermissionMapper.java  |  8 ++-
 .../auth/jdbc/permission/PermissionService.java | 19 ++++---
 .../SharingProfilePermissionService.java        |  4 +-
 .../jdbc/permission/SystemPermissionMapper.java | 10 +++-
 .../permission/SystemPermissionService.java     | 35 ++++++------
 .../jdbc/permission/SystemPermissionSet.java    | 19 ++++++-
 .../jdbc/permission/UserPermissionService.java  |  4 +-
 .../guacamole/auth/jdbc/user/ModeledUser.java   | 59 +++++++++++++++++---
 16 files changed, 198 insertions(+), 99 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/0a69630c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java
index 91ad11d..405b237 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java
@@ -23,7 +23,6 @@ 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.HashSet;
 import java.util.Set;
 import org.apache.guacamole.GuacamoleException;
@@ -58,26 +57,23 @@ public class ActiveConnectionPermissionService
     private Provider<ActiveConnectionPermissionSet> activeConnectionPermissionSetProvider;
 
     @Override
-    public ObjectPermission retrievePermission(ModeledAuthenticatedUser user,
+    public boolean hasPermission(ModeledAuthenticatedUser user,
             ModeledUser targetUser, ObjectPermission.Type type,
-            String identifier) throws GuacamoleException {
+            String identifier, boolean inherit) throws GuacamoleException {
 
         // Retrieve permissions
-        Set<ObjectPermission> permissions = retrievePermissions(user, targetUser);
+        Set<ObjectPermission> permissions = retrievePermissions(user, targetUser, inherit);
 
-        // If retrieved permissions contains the requested permission, return it
+        // Permission is granted if retrieved permissions contains the
+        // requested permission
         ObjectPermission permission = new ObjectPermission(type, identifier); 
-        if (permissions.contains(permission))
-            return permission;
-
-        // Otherwise, no such permission
-        return null;
+        return permissions.contains(permission);
 
     }
 
     @Override
     public Set<ObjectPermission> retrievePermissions(ModeledAuthenticatedUser user,
-            ModeledUser targetUser) throws GuacamoleException {
+            ModeledUser targetUser, boolean inherit) throws GuacamoleException {
 
         // Retrieve permissions only if allowed
         if (canReadPermissions(user, targetUser)) {
@@ -113,9 +109,9 @@ public class ActiveConnectionPermissionService
     @Override
     public Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user,
             ModeledUser targetUser, Collection<ObjectPermission.Type> permissionTypes,
-            Collection<String> identifiers) throws GuacamoleException {
+            Collection<String> identifiers, boolean inherit) throws GuacamoleException {
 
-        Set<ObjectPermission> permissions = retrievePermissions(user, targetUser);
+        Set<ObjectPermission> permissions = retrievePermissions(user, targetUser, inherit);
         Collection<String> accessibleObjects = new ArrayList<String>(permissions.size());
 
         // For each identifier/permission combination
@@ -138,11 +134,11 @@ public class ActiveConnectionPermissionService
 
     @Override
     public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser) throws GuacamoleException {
+            ModeledUser targetUser, boolean inherit) throws GuacamoleException {
     
         // Create permission set for requested user
         ActiveConnectionPermissionSet permissionSet = activeConnectionPermissionSetProvider.get();
-        permissionSet.init(user, targetUser);
+        permissionSet.init(user, targetUser, inherit);
 
         return permissionSet;
  

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/0a69630c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java
index 68fc3ed..3027d81 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java
@@ -51,11 +51,11 @@ public class ConnectionGroupPermissionService extends ModeledObjectPermissionSer
 
     @Override
     public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser) throws GuacamoleException {
+            ModeledUser targetUser, boolean inherit) throws GuacamoleException {
 
         // Create permission set for requested user
         ObjectPermissionSet permissionSet = connectionGroupPermissionSetProvider.get();
-        permissionSet.init(user, targetUser);
+        permissionSet.init(user, targetUser, inherit);
 
         return permissionSet;
         

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/0a69630c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java
index 80c4b0b..19c30c0 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java
@@ -51,11 +51,11 @@ public class ConnectionPermissionService extends ModeledObjectPermissionService
 
     @Override
     public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser) throws GuacamoleException {
+            ModeledUser targetUser, boolean inherit) throws GuacamoleException {
 
         // Create permission set for requested user
         ObjectPermissionSet permissionSet = connectionPermissionSetProvider.get();
-        permissionSet.init(user, targetUser);
+        permissionSet.init(user, targetUser, inherit);
 
         return permissionSet;
         

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/0a69630c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
index 9197217..30ea5d7 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
@@ -105,7 +105,7 @@ public abstract class ModeledObjectPermissionService
             affectedIdentifiers.add(permission.getObjectIdentifier());
 
         // Determine subset of affected identifiers that we have admin access to
-        ObjectPermissionSet affectedPermissionSet = getPermissionSet(user, user.getUser());
+        ObjectPermissionSet affectedPermissionSet = getPermissionSet(user, user.getUser(), true);
         Collection<String> allowedSubset = affectedPermissionSet.getAccessibleObjects(
             Collections.singleton(ObjectPermission.Type.ADMINISTER),
             affectedIdentifiers
@@ -154,21 +154,13 @@ public abstract class ModeledObjectPermissionService
     }
 
     @Override
-    public ObjectPermission retrievePermission(ModeledAuthenticatedUser user,
+    public boolean hasPermission(ModeledAuthenticatedUser user,
             ModeledUser targetUser, ObjectPermission.Type type,
-            String identifier) throws GuacamoleException {
+            String identifier, boolean inherit) throws GuacamoleException {
 
         // Retrieve permissions only if allowed
-        if (canReadPermissions(user, targetUser)) {
-
-            // Read permission from database, return null if not found
-            ObjectPermissionModel model = getPermissionMapper().selectOne(targetUser.getModel(), type, identifier);
-            if (model == null)
-                return null;
-
-            return getPermissionInstance(model);
-
-        }
+        if (canReadPermissions(user, targetUser))
+            return getPermissionMapper().selectOne(targetUser.getModel(), type, identifier, inherit) != null;
 
         // User cannot read this user's permissions
         throw new GuacamoleSecurityException("Permission denied.");
@@ -178,7 +170,8 @@ public abstract class ModeledObjectPermissionService
     @Override
     public Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user,
             ModeledUser targetUser, Collection<ObjectPermission.Type> permissions,
-            Collection<String> identifiers) throws GuacamoleException {
+            Collection<String> identifiers, boolean inherit)
+            throws GuacamoleException {
 
         // Nothing is always accessible
         if (identifiers.isEmpty())
@@ -192,7 +185,7 @@ public abstract class ModeledObjectPermissionService
                 return identifiers;
 
             // Otherwise, return explicitly-retrievable identifiers
-            return getPermissionMapper().selectAccessibleIdentifiers(targetUser.getModel(), permissions, identifiers);
+            return getPermissionMapper().selectAccessibleIdentifiers(targetUser.getModel(), permissions, identifiers, inherit);
             
         }
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/0a69630c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java
index 2800845..4d0fcf6 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java
@@ -92,7 +92,7 @@ public abstract class ModeledPermissionService<PermissionSetType extends Permiss
             permissions.add(getPermissionInstance(model));
 
         return permissions;
-        
+
     }
 
     /**
@@ -111,7 +111,7 @@ public abstract class ModeledPermissionService<PermissionSetType extends Permiss
      */
     protected abstract ModelType getModelInstance(ModeledUser targetUser,
             PermissionType permission);
-    
+
     /**
      * Returns a collection of model objects which are based on the given
      * permissions and target user.
@@ -129,7 +129,7 @@ public abstract class ModeledPermissionService<PermissionSetType extends Permiss
     protected Collection<ModelType> getModelInstances(ModeledUser targetUser,
             Collection<PermissionType> permissions) {
 
-        // Create new collection of models by manually converting each permission 
+        // Create new collection of models by manually converting each permission
         Collection<ModelType> models = new ArrayList<ModelType>(permissions.size());
         for (PermissionType permission : permissions)
             models.add(getModelInstance(targetUser, permission));
@@ -140,15 +140,15 @@ public abstract class ModeledPermissionService<PermissionSetType extends Permiss
 
     @Override
     public Set<PermissionType> retrievePermissions(ModeledAuthenticatedUser user,
-            ModeledUser targetUser) throws GuacamoleException {
+            ModeledUser targetUser, boolean inherit) throws GuacamoleException {
 
         // Retrieve permissions only if allowed
         if (canReadPermissions(user, targetUser))
-            return getPermissionInstances(getPermissionMapper().select(targetUser.getModel()));
+            return getPermissionInstances(getPermissionMapper().select(targetUser.getModel(), inherit));
 
         // User cannot read this user's permissions
         throw new GuacamoleSecurityException("Permission denied.");
-        
+
     }
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/0a69630c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java
index f744fbf..e5efad0 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java
@@ -36,20 +36,26 @@ public interface ObjectPermissionMapper extends PermissionMapper<ObjectPermissio
      *
      * @param entity
      *     The entity to retrieve permissions for.
-     * 
+     *
      * @param type
      *     The type of permission to return.
-     * 
+     *
      * @param identifier
      *     The identifier of the object affected by the permission to return.
      *
+     * @param inherit
+     *     Whether permissions inherited through user groups should be taken
+     *     into account. If false, only permissions granted directly will be
+     *     included.
+     *
      * @return
      *     The requested permission, or null if no such permission is granted
      *     to the given entity for the given object.
      */
     ObjectPermissionModel selectOne(@Param("entity") EntityModel entity,
             @Param("type") ObjectPermission.Type type,
-            @Param("identifier") String identifier);
+            @Param("identifier") String identifier,
+            @Param("inherit") boolean inherit);
 
     /**
      * Retrieves the subset of the given identifiers for which the given entity
@@ -67,12 +73,18 @@ public interface ObjectPermissionMapper extends PermissionMapper<ObjectPermissio
      *     The identifiers of the objects affected by the permissions being
      *     checked.
      *
+     * @param inherit
+     *     Whether permissions inherited through user groups should be taken
+     *     into account. If false, only permissions granted directly will be
+     *     included.
+     *
      * @return
      *     A collection containing the subset of identifiers for which at least
      *     one of the specified permissions is granted.
      */
     Collection<String> selectAccessibleIdentifiers(@Param("entity") EntityModel entity,
             @Param("permissions") Collection<ObjectPermission.Type> permissions,
-            @Param("identifiers") Collection<String> identifiers);
+            @Param("identifiers") Collection<String> identifiers,
+            @Param("inherit") boolean inherit);
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/0a69630c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java
index 5eead24..fa1ee2d 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java
@@ -35,31 +35,36 @@ public interface ObjectPermissionService
     extends PermissionService<ObjectPermissionSet, ObjectPermission> {
 
     /**
-     * Retrieves the permission of the given type associated with the given
-     * user and object, if it exists. If no such permission exists, null is
+     * Returns whether the permission of the given type and associated with the
+     * given object has been granted to the given user.
      *
      * @param user
      *     The user retrieving the permission.
      *
      * @param targetUser
      *     The user associated with the permission to be retrieved.
-     * 
+     *
      * @param type
      *     The type of permission to retrieve.
      *
      * @param identifier
      *     The identifier of the object affected by the permission to return.
      *
+     * @param inherit
+     *     Whether permissions inherited through user groups should be taken
+     *     into account. If false, only permissions granted directly will be
+     *     included.
+     *
      * @return
-     *     The permission of the given type associated with the given user and
-     *     object, or null if no such permission exists.
+     *     true if permission of the given type and associated with the given
+     *     object has been granted to the given user, false otherwise.
      *
      * @throws GuacamoleException
      *     If an error occurs while retrieving the requested permission.
      */
-    ObjectPermission retrievePermission(ModeledAuthenticatedUser user,
+    boolean hasPermission(ModeledAuthenticatedUser user,
             ModeledUser targetUser, ObjectPermission.Type type,
-            String identifier) throws GuacamoleException;
+            String identifier, boolean inherit) throws GuacamoleException;
 
     /**
      * Retrieves the subset of the given identifiers for which the given user
@@ -80,6 +85,11 @@ public interface ObjectPermissionService
      *     The identifiers of the objects affected by the permissions being
      *     checked.
      *
+     * @param inherit
+     *     Whether permissions inherited through user groups should be taken
+     *     into account. If false, only permissions granted directly will be
+     *     included.
+     *
      * @return
      *     A collection containing the subset of identifiers for which at least
      *     one of the specified permissions is granted.
@@ -89,6 +99,7 @@ public interface ObjectPermissionService
      */
     Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user,
             ModeledUser targetUser, Collection<ObjectPermission.Type> permissions,
-            Collection<String> identifiers) throws GuacamoleException;
+            Collection<String> identifiers, boolean inherit)
+            throws GuacamoleException;
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/0a69630c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java
index 712a422..cedb45d 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java
@@ -43,6 +43,12 @@ public abstract class ObjectPermissionSet extends RestrictedObject
     private ModeledUser user;
 
     /**
+     * Whether permissions inherited through user groups should be taken into
+     * account. If false, only permissions granted directly will be included.
+     */
+    boolean inherit;
+
+    /**
      * Creates a new ObjectPermissionSet. The resulting permission set
      * must still be initialized by a call to init(), or the information
      * necessary to read and modify this set will be missing.
@@ -60,10 +66,17 @@ public abstract class ObjectPermissionSet extends RestrictedObject
      *
      * @param user
      *     The user to whom the permissions in this set are granted.
+     *
+     * @param inherit
+     *     Whether permissions inherited through user groups should be taken
+     *     into account. If false, only permissions granted directly will be
+     *     included.
      */
-    public void init(ModeledAuthenticatedUser currentUser, ModeledUser user) {
+    public void init(ModeledAuthenticatedUser currentUser, ModeledUser user,
+            boolean inherit) {
         super.init(currentUser);
         this.user = user;
+        this.inherit = inherit;
     }
 
     /**
@@ -75,16 +88,16 @@ public abstract class ObjectPermissionSet extends RestrictedObject
      *     permissions contained within this permission set.
      */
     protected abstract ObjectPermissionService getObjectPermissionService();
- 
+
     @Override
     public Set<ObjectPermission> getPermissions() throws GuacamoleException {
-        return getObjectPermissionService().retrievePermissions(getCurrentUser(), user);
+        return getObjectPermissionService().retrievePermissions(getCurrentUser(), user, inherit);
     }
 
     @Override
     public boolean hasPermission(ObjectPermission.Type permission,
             String identifier) throws GuacamoleException {
-        return getObjectPermissionService().retrievePermission(getCurrentUser(), user, permission, identifier) != null;
+        return getObjectPermissionService().hasPermission(getCurrentUser(), user, permission, identifier, inherit);
     }
 
     @Override
@@ -102,7 +115,7 @@ public abstract class ObjectPermissionSet extends RestrictedObject
     @Override
     public Collection<String> getAccessibleObjects(Collection<ObjectPermission.Type> permissions,
             Collection<String> identifiers) throws GuacamoleException {
-        return getObjectPermissionService().retrieveAccessibleIdentifiers(getCurrentUser(), user, permissions, identifiers);
+        return getObjectPermissionService().retrieveAccessibleIdentifiers(getCurrentUser(), user, permissions, identifiers, inherit);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/0a69630c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java
index 7b476b3..1c2d23b 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java
@@ -38,10 +38,16 @@ public interface PermissionMapper<PermissionType> {
      * @param entity
      *     The entity to retrieve permissions for.
      *
+     * @param inherit
+     *     Whether permissions inherited through user groups should be taken
+     *     into account. If false, only permissions granted directly will be
+     *     included.
+     *
      * @return
      *     All permissions associated with the given entity.
      */
-    Collection<PermissionType> select(@Param("entity") EntityModel entity);
+    Collection<PermissionType> select(@Param("entity") EntityModel entity,
+            @Param("inherit") boolean inherit);
 
     /**
      * Inserts the given permissions into the database. If any permissions

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/0a69630c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java
index 12b046b..6e59634 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java
@@ -19,16 +19,11 @@
 
 package org.apache.guacamole.auth.jdbc.permission;
 
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
 import org.apache.guacamole.auth.jdbc.user.ModeledUser;
 import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.GuacamoleSecurityException;
-import org.apache.guacamole.net.auth.permission.ObjectPermission;
-import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
 import org.apache.guacamole.net.auth.permission.Permission;
 import org.apache.guacamole.net.auth.permission.PermissionSet;
 
@@ -59,6 +54,11 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
      *     The user to whom the permissions in the returned permission set are
      *     granted.
      *
+     * @param inherit
+     *     Whether permissions inherited through user groups should be taken
+     *     into account. If false, only permissions granted directly will be
+     *     included.
+     *
      * @return
      *     A permission set that contains all permissions associated with the
      *     given user, and can be used to manipulate that user's permissions.
@@ -69,7 +69,7 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
      *     user is denied.
      */
     PermissionSetType getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser) throws GuacamoleException;
+            ModeledUser targetUser, boolean inherit) throws GuacamoleException;
 
     /**
      * Retrieves all permissions associated with the given user.
@@ -80,6 +80,11 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
      * @param targetUser
      *     The user associated with the permissions to be retrieved.
      *
+     * @param inherit
+     *     Whether permissions inherited through user groups should be taken
+     *     into account. If false, only permissions granted directly will be
+     *     included.
+     *
      * @return
      *     The permissions associated with the given user.
      *
@@ -87,7 +92,7 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
      *     If an error occurs while retrieving the requested permissions.
      */
     Set<PermissionType> retrievePermissions(ModeledAuthenticatedUser user,
-            ModeledUser targetUser) throws GuacamoleException;
+            ModeledUser targetUser, boolean inherit) throws GuacamoleException;
 
     /**
      * Creates the given permissions within the database. If any permissions

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/0a69630c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java
index ac16fc2..3cdf9d1 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java
@@ -51,11 +51,11 @@ public class SharingProfilePermissionService extends ModeledObjectPermissionServ
 
     @Override
     public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser) throws GuacamoleException {
+            ModeledUser targetUser, boolean inherit) throws GuacamoleException {
 
         // Create permission set for requested user
         ObjectPermissionSet permissionSet = sharingProfilePermissionSetProvider.get();
-        permissionSet.init(user, targetUser);
+        permissionSet.init(user, targetUser, inherit);
 
         return permissionSet;
         

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/0a69630c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java
index 738062c..c05f405 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java
@@ -34,15 +34,21 @@ public interface SystemPermissionMapper extends PermissionMapper<SystemPermissio
      *
      * @param entity
      *     The entity to retrieve permissions for.
-     * 
+     *
      * @param type
      *     The type of permission to return.
      *
+     * @param inherit
+     *     Whether permissions inherited through user groups should be taken
+     *     into account. If false, only permissions granted directly will be
+     *     included.
+     *
      * @return
      *     The requested permission, or null if no such permission is granted
      *     to the given entity.
      */
     SystemPermissionModel selectOne(@Param("entity") EntityModel entity,
-            @Param("type") SystemPermission.Type type);
+            @Param("type") SystemPermission.Type type,
+            @Param("inherit") boolean inherit);
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/0a69630c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
index e50a47f..5909569 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
@@ -75,11 +75,11 @@ public class SystemPermissionService
 
     @Override
     public SystemPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser) throws GuacamoleException {
+            ModeledUser targetUser, boolean inherit) throws GuacamoleException {
 
         // Create permission set for requested user
         SystemPermissionSet permissionSet = systemPermissionSetProvider.get();
-        permissionSet.init(user, targetUser);
+        permissionSet.init(user, targetUser, inherit);
 
         return permissionSet;
         
@@ -123,8 +123,9 @@ public class SystemPermissionService
     }
 
     /**
-     * Retrieves the permission of the given type associated with the given
-     * user, if it exists. If no such permission exists, null is returned.
+     * Retrieves whether the permission of the given type has been granted to
+     * the given user. Permission inheritance through group membership is taken
+     * into account.
      *
      * @param user
      *     The user retrieving the permission.
@@ -135,27 +136,25 @@ public class SystemPermissionService
      * @param type
      *     The type of permission to retrieve.
      *
+     * @param inherit
+     *     Whether permissions inherited through user groups should be taken
+     *     into account. If false, only permissions granted directly will be
+     *     included.
+     *
      * @return
-     *     The permission of the given type associated with the given user, or
-     *     null if no such permission exists.
+     *     true if permission of the given type has been granted to the given
+     *     user, false otherwise.
      *
      * @throws GuacamoleException
      *     If an error occurs while retrieving the requested permission.
      */
-    public SystemPermission retrievePermission(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, SystemPermission.Type type) throws GuacamoleException {
+    public boolean hasPermission(ModeledAuthenticatedUser user,
+            ModeledUser targetUser, SystemPermission.Type type,
+            boolean inherit) throws GuacamoleException {
 
         // Retrieve permissions only if allowed
-        if (canReadPermissions(user, targetUser)) {
-
-            // Read permission from database, return null if not found
-            SystemPermissionModel model = getPermissionMapper().selectOne(targetUser.getModel(), type);
-            if (model == null)
-                return null;
-
-            return getPermissionInstance(model);
-
-        }
+        if (canReadPermissions(user, targetUser))
+            return getPermissionMapper().selectOne(targetUser.getModel(), type, inherit) != null;
 
         // User cannot read this user's permissions
         throw new GuacamoleSecurityException("Permission denied.");

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/0a69630c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java
index 9c84a84..bb5af11 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java
@@ -43,6 +43,12 @@ public class SystemPermissionSet extends RestrictedObject
     private ModeledUser user;
 
     /**
+     * Whether permissions inherited through user groups should be taken into
+     * account. If false, only permissions granted directly will be included.
+     */
+    private boolean inherit;
+
+    /**
      * Service for reading and manipulating system permissions.
      */
     @Inject
@@ -66,21 +72,28 @@ public class SystemPermissionSet extends RestrictedObject
      *
      * @param user
      *     The user to whom the permissions in this set are granted.
+     *
+     * @param inherit
+     *     Whether permissions inherited through user groups should be taken
+     *     into account. If false, only permissions granted directly will be
+     *     included.
      */
-    public void init(ModeledAuthenticatedUser currentUser, ModeledUser user) {
+    public void init(ModeledAuthenticatedUser currentUser, ModeledUser user,
+            boolean inherit) {
         super.init(currentUser);
         this.user = user;
+        this.inherit = inherit;
     }
 
     @Override
     public Set<SystemPermission> getPermissions() throws GuacamoleException {
-        return systemPermissionService.retrievePermissions(getCurrentUser(), user);
+        return systemPermissionService.retrievePermissions(getCurrentUser(), user, inherit);
     }
 
     @Override
     public boolean hasPermission(SystemPermission.Type permission)
             throws GuacamoleException {
-        return systemPermissionService.retrievePermission(getCurrentUser(), user, permission) != null;
+        return systemPermissionService.hasPermission(getCurrentUser(), user, permission, inherit);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/0a69630c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java
index d56ed28..8e65862 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java
@@ -51,11 +51,11 @@ public class UserPermissionService extends ModeledObjectPermissionService {
 
     @Override
     public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser) throws GuacamoleException {
+            ModeledUser targetUser, boolean inherit) throws GuacamoleException {
 
         // Create permission set for requested user
         ObjectPermissionSet permissionSet = userPermissionSetProvider.get();
-        permissionSet.init(user, targetUser);
+        permissionSet.init(user, targetUser, inherit);
 
         return permissionSet;
         

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/0a69630c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
index 583aa7f..39f1636 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
@@ -350,37 +350,37 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
     @Override
     public SystemPermissionSet getSystemPermissions()
             throws GuacamoleException {
-        return systemPermissionService.getPermissionSet(getCurrentUser(), this);
+        return systemPermissionService.getPermissionSet(getCurrentUser(), this, false);
     }
 
     @Override
     public ObjectPermissionSet getConnectionPermissions()
             throws GuacamoleException {
-        return connectionPermissionService.getPermissionSet(getCurrentUser(), this);
+        return connectionPermissionService.getPermissionSet(getCurrentUser(), this, false);
     }
 
     @Override
     public ObjectPermissionSet getConnectionGroupPermissions()
             throws GuacamoleException {
-        return connectionGroupPermissionService.getPermissionSet(getCurrentUser(), this);
+        return connectionGroupPermissionService.getPermissionSet(getCurrentUser(), this, false);
     }
 
     @Override
     public ObjectPermissionSet getSharingProfilePermissions()
             throws GuacamoleException {
-        return sharingProfilePermissionService.getPermissionSet(getCurrentUser(), this);
+        return sharingProfilePermissionService.getPermissionSet(getCurrentUser(), this, false);
     }
 
     @Override
     public ObjectPermissionSet getActiveConnectionPermissions()
             throws GuacamoleException {
-        return activeConnectionPermissionService.getPermissionSet(getCurrentUser(), this);
+        return activeConnectionPermissionService.getPermissionSet(getCurrentUser(), this, false);
     }
 
     @Override
     public ObjectPermissionSet getUserPermissions()
             throws GuacamoleException {
-        return userPermissionService.getPermissionSet(getCurrentUser(), this);
+        return userPermissionService.getPermissionSet(getCurrentUser(), this, false);
     }
 
     @Override
@@ -855,7 +855,52 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
 
     @Override
     public Permissions getEffectivePermissions() throws GuacamoleException {
-        return this;
+        return new Permissions() {
+
+            @Override
+            public ObjectPermissionSet getActiveConnectionPermissions()
+                    throws GuacamoleException {
+                return activeConnectionPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true);
+            }
+
+            @Override
+            public ObjectPermissionSet getConnectionGroupPermissions()
+                    throws GuacamoleException {
+                return connectionGroupPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true);
+            }
+
+            @Override
+            public ObjectPermissionSet getConnectionPermissions()
+                    throws GuacamoleException {
+                return connectionPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true);
+            }
+
+            @Override
+            public ObjectPermissionSet getSharingProfilePermissions()
+                    throws GuacamoleException {
+                return sharingProfilePermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true);
+            }
+
+            @Override
+            public SystemPermissionSet getSystemPermissions()
+                    throws GuacamoleException {
+                return systemPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true);
+            }
+
+            @Override
+            public ObjectPermissionSet getUserPermissions()
+                    throws GuacamoleException {
+                return userPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true);
+            }
+
+            @Override
+            public ObjectPermissionSet getUserGroupPermissions()
+                    throws GuacamoleException {
+                // FIXME: STUB
+                return new SimpleObjectPermissionSet();
+            }
+
+        };
     }
 
 }


[25/38] guacamole-client git commit: GUACAMOLE-220: Update SQL Server mapping with respect to user group support.

Posted by vn...@apache.org.
http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
index 22a0cc7..4d4a3cc 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
@@ -44,8 +44,9 @@
             [guacamole_user_history].end_date
         FROM [guacamole_user_history]
         JOIN [guacamole_user] ON [guacamole_user_history].user_id = [guacamole_user].user_id
+        JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
         WHERE
-            [guacamole_user].username = #{username,jdbcType=VARCHAR}
+            [guacamole_entity].name = #{username,jdbcType=VARCHAR}
         ORDER BY
             [guacamole_user_history].start_date DESC,
             [guacamole_user_history].end_date DESC
@@ -66,7 +67,10 @@
         VALUES (
             #{record.remoteHost,jdbcType=VARCHAR},
             (SELECT user_id FROM [guacamole_user]
-             WHERE username = #{record.username,jdbcType=VARCHAR}),
+             JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
+             WHERE
+                   [guacamole_entity].name = #{record.username,jdbcType=VARCHAR}
+               AND [guacamole_entity].type = 'USER'),
             #{record.username,jdbcType=VARCHAR},
             #{record.startDate,jdbcType=TIMESTAMP},
             #{record.endDate,jdbcType=TIMESTAMP}
@@ -79,7 +83,10 @@
         UPDATE [guacamole_user_history]
         SET remote_host = #{record.remoteHost,jdbcType=VARCHAR},
             user_id     = (SELECT user_id FROM [guacamole_user]
-                           WHERE username = #{record.username,jdbcType=VARCHAR}),
+                           JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
+                           WHERE
+                                   [guacamole_entity].name = #{record.username,jdbcType=VARCHAR}
+                               AND [guacamole_entity].type = 'USER'),
             username    = #{record.username,jdbcType=VARCHAR},
             start_date  = #{record.startDate,jdbcType=TIMESTAMP},
             end_date    = #{record.endDate,jdbcType=TIMESTAMP}
@@ -105,7 +112,10 @@
                 [guacamole_user_history].user_id IN (
                     SELECT user_id
                     FROM [guacamole_user]
-                    WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
+                    JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
+                    WHERE
+                            POSITION(#{term.term,jdbcType=VARCHAR} IN [guacamole_entity].name) > 0
+                        AND [guacamole_entity].type = 'USER'),
                 )
 
                 <if test="term.startDate != null and term.endDate != null">
@@ -144,7 +154,11 @@
         <!-- Restrict to readable users -->
         JOIN [guacamole_user_permission] ON
                 [guacamole_user_history].user_id       = [guacamole_user_permission].affected_user_id
-            AND [guacamole_user_permission].user_id    = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_user_permission].entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND [guacamole_user_permission].permission = 'READ'
 
         <!-- Search terms -->
@@ -155,7 +169,10 @@
                 [guacamole_user_history].user_id IN (
                     SELECT user_id
                     FROM [guacamole_user]
-                    WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
+                    JOIN [guacamole_entity] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
+                    WHERE
+                            POSITION(#{term.term,jdbcType=VARCHAR} IN [guacamole_entity].name) > 0
+                        AND [guacamole_entity].type = 'USER'
                 )
 
                 <if test="term.startDate != null and term.endDate != null">

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml
new file mode 100644
index 0000000..aed0247
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMapper.xml
@@ -0,0 +1,229 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.usergroup.UserGroupMapper" >
+
+    <!-- Result mapper for user group objects -->
+    <resultMap id="UserGroupResultMap" type="org.apache.guacamole.auth.jdbc.usergroup.UserGroupModel" >
+
+        <!-- User group properties -->
+        <id     column="user_group_id" property="objectID"   jdbcType="INTEGER"/>
+        <result column="entity_id"     property="entityID"   jdbcType="INTEGER"/>
+        <result column="name"          property="identifier" jdbcType="VARCHAR"/>
+        <result column="disabled"      property="disabled"   jdbcType="BOOLEAN"/>
+
+        <!-- Arbitrary attributes -->
+        <collection property="arbitraryAttributes" resultSet="arbitraryAttributes"
+                    ofType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel"
+                    column="user_group_id" foreignColumn="user_group_id">
+            <result property="name"     column="attribute_name"  jdbcType="VARCHAR"/>
+            <result property="value"    column="attribute_value" jdbcType="VARCHAR"/>
+        </collection>
+
+    </resultMap>
+
+    <!-- Select all group names -->
+    <select id="selectIdentifiers" resultType="string">
+        SELECT name
+        FROM [guacamole_entity]
+        WHERE [guacamole_entity].type = 'USER_GROUP'
+    </select>
+
+    <!-- Select names of all readable groups -->
+    <select id="selectReadableIdentifiers" resultType="string">
+        SELECT [guacamole_entity].name
+        FROM [guacamole_user_group]
+        JOIN [guacamole_entity] ON [guacamole_user_group].entity_id = [guacamole_entity].entity_id
+        JOIN [guacamole_user_group_permission] ON affected_user_group_id = [guacamole_user_group].user_group_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_user_group_permission].entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND [guacamole_entity].type = 'USER_GROUP'
+            AND permission = 'READ'
+    </select>
+
+    <!-- Select multiple groups by name -->
+    <select id="select" resultMap="UserGroupResultMap"
+            resultSets="users,arbitraryAttributes">
+
+        SELECT
+            [guacamole_user_group].user_group_id,
+            [guacamole_entity].entity_id,
+            [guacamole_entity].name,
+            disabled
+        FROM [guacamole_user_group]
+        JOIN [guacamole_entity] ON [guacamole_user_group].entity_id = [guacamole_entity].entity_id
+        WHERE [guacamole_entity].name IN
+            <foreach collection="identifiers" item="identifier"
+                     open="(" separator="," close=")">
+                #{identifier,jdbcType=VARCHAR}
+            </foreach>
+            AND [guacamole_entity].type = 'USER_GROUP';
+
+        SELECT
+            [guacamole_user_group_attribute].user_group_id,
+            [guacamole_user_group_attribute].attribute_name,
+            [guacamole_user_group_attribute].attribute_value
+        FROM [guacamole_user_group_attribute]
+        JOIN [guacamole_user_group] ON [guacamole_user_group].user_group_id = [guacamole_user_group_attribute].user_group_id
+        JOIN [guacamole_entity] ON [guacamole_user_group].entity_id = [guacamole_entity].entity_id
+        WHERE [guacamole_entity].name IN
+            <foreach collection="identifiers" item="identifier"
+                     open="(" separator="," close=")">
+                #{identifier,jdbcType=VARCHAR}
+            </foreach>
+            AND [guacamole_entity].type = 'USER_GROUP';
+
+    </select>
+
+    <!-- Select multiple groups by name only if readable -->
+    <select id="selectReadable" resultMap="UserGroupResultMap"
+            resultSets="users,arbitraryAttributes">
+
+        SELECT
+            [guacamole_user_group].user_group_id,
+            [guacamole_entity].entity_id,
+            [guacamole_entity].name,
+            disabled
+        FROM [guacamole_user_group]
+        JOIN [guacamole_entity] ON [guacamole_user_group].entity_id = [guacamole_entity].entity_id
+        JOIN [guacamole_user_group_permission] ON affected_user_group_id = [guacamole_user_group].user_group_id
+        WHERE [guacamole_entity].name IN
+            <foreach collection="identifiers" item="identifier"
+                     open="(" separator="," close=")">
+                #{identifier,jdbcType=VARCHAR}
+            </foreach>
+            AND [guacamole_entity].type = 'USER_GROUP'
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_user_group_permission].entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND permission = 'READ';
+
+        SELECT
+            [guacamole_user_group_attribute].user_group_id,
+            [guacamole_user_group_attribute].attribute_name,
+            [guacamole_user_group_attribute].attribute_value
+        FROM [guacamole_user_group_attribute]
+        JOIN [guacamole_user_group] ON [guacamole_user_group].user_group_id = [guacamole_user_group_attribute].user_group_id
+        JOIN [guacamole_entity] ON [guacamole_user_group].entity_id = [guacamole_entity].entity_id
+        JOIN [guacamole_user_group_permission] ON affected_user_group_id = [guacamole_user_group].user_group_id
+        WHERE [guacamole_entity].name IN
+            <foreach collection="identifiers" item="identifier"
+                     open="(" separator="," close=")">
+                #{identifier,jdbcType=VARCHAR}
+            </foreach>
+            AND [guacamole_entity].type = 'USER_GROUP'
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_user_group_permission].entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND permission = 'READ';
+
+    </select>
+
+    <!-- Select single group by name -->
+    <select id="selectOne" resultMap="UserGroupResultMap"
+            resultSets="users,arbitraryAttributes">
+
+        SELECT
+            [guacamole_user_group].user_group_id,
+            [guacamole_entity].entity_id,
+            [guacamole_entity].name,
+            disabled
+        FROM [guacamole_user_group]
+        JOIN [guacamole_entity] ON [guacamole_user_group].entity_id = [guacamole_entity].entity_id
+        WHERE
+            [guacamole_entity].name = #{name,jdbcType=VARCHAR}
+            AND [guacamole_entity].type = 'USER_GROUP';
+
+        SELECT
+            [guacamole_user_group_attribute].user_group_id,
+            [guacamole_user_group_attribute].attribute_name,
+            [guacamole_user_group_attribute].attribute_value
+        FROM [guacamole_user_group_attribute]
+        JOIN [guacamole_user_group] ON [guacamole_user_group].user_group_id = [guacamole_user_group_attribute].user_group_id
+        JOIN [guacamole_entity] ON [guacamole_user_group].entity_id = [guacamole_entity].entity_id
+        WHERE
+            [guacamole_entity].name = #{name,jdbcType=VARCHAR}
+            AND [guacamole_entity].type = 'USER_GROUP'
+
+    </select>
+
+    <!-- Delete single group by name -->
+    <delete id="delete">
+        DELETE FROM [guacamole_entity]
+        WHERE
+            name = #{identifier,jdbcType=VARCHAR}
+            AND type = 'USER_GROUP'
+    </delete>
+
+    <!-- Insert single group -->
+    <insert id="insert" useGeneratedKeys="true" keyProperty="object.objectID"
+            parameterType="org.apache.guacamole.auth.jdbc.usergroup.UserGroupModel">
+
+        INSERT INTO [guacamole_user_group] (
+            entity_id,
+            disabled
+        )
+        VALUES (
+            #{object.entityID,jdbcType=VARCHAR},
+            #{object.disabled,jdbcType=BOOLEAN}
+        )
+
+    </insert>
+
+    <!-- Update single group -->
+    <update id="update" parameterType="org.apache.guacamole.auth.jdbc.usergroup.UserGroupModel">
+        UPDATE [guacamole_user_group]
+        SET disabled = #{object.disabled,jdbcType=BOOLEAN}
+        WHERE user_group_id = #{object.objectID,jdbcType=VARCHAR}
+    </update>
+
+    <!-- Delete attributes associated with group -->
+    <delete id="deleteAttributes">
+        DELETE FROM [guacamole_user_group_attribute]
+        WHERE user_group_id = #{object.objectID,jdbcType=INTEGER}
+    </delete>
+
+    <!-- Insert attributes for group -->
+    <insert id="insertAttributes" parameterType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel">
+        INSERT INTO [guacamole_user_group_attribute] (
+            user_group_id,
+            attribute_name,
+            attribute_value
+        )
+        VALUES
+            <foreach collection="object.arbitraryAttributes" item="attribute" separator=",">
+                (#{object.objectID,jdbcType=INTEGER},
+                 #{attribute.name,jdbcType=VARCHAR},
+                 #{attribute.value,jdbcType=VARCHAR})
+            </foreach>
+    </insert>
+
+</mapper>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml
new file mode 100644
index 0000000..2092f24
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserGroupMapper" >
+
+    <!-- Select the names of all member user groups -->
+    <select id="selectChildIdentifiers" resultType="string">
+        SELECT name
+        FROM [guacamole_user_group_member]
+        JOIN [guacamole_entity] ON [guacamole_entity].entity_id = [guacamole_user_group_member].member_entity_id
+        WHERE
+            [guacamole_user_group_member].user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            AND [guacamole_entity].type = 'USER_GROUP'
+    </select>
+
+    <!-- Select the names of all readable member user groups -->
+    <select id="selectReadableChildIdentifiers" resultType="string">
+        SELECT [guacamole_entity].name
+        FROM [guacamole_user_group_member]
+        JOIN [guacamole_entity] ON [guacamole_entity].entity_id = [guacamole_user_group_member].member_entity_id
+        JOIN [guacamole_user_group] ON [guacamole_user_group].entity_id = [guacamole_entity].entity_id
+        JOIN [guacamole_user_group_permission] ON affected_user_group_id = [guacamole_user_group].user_group_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_user_group_permission].entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND [guacamole_user_group_member].user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            AND [guacamole_entity].type = 'USER_GROUP'
+            AND permission = 'READ'
+    </select>
+
+    <!-- Delete member groups by name -->
+    <delete id="delete">
+        DELETE [guacamole_user_group_member]
+        FROM [guacamole_user_group_member]
+        JOIN [guacamole_entity] ON [guacamole_entity].entity_id = member_entity_id
+        WHERE
+            user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            AND [guacamole_entity].type = 'USER_GROUP'
+            AND [guacamole_entity].name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+    </delete>
+
+    <!-- Insert member groups by name -->
+    <insert id="insert">
+        INSERT INTO [guacamole_user_group_member] (
+            user_group_id,
+            member_entity_id
+        )
+        SELECT DISTINCT
+            #{parent.objectID,jdbcType=INTEGER},
+            [guacamole_entity].entity_id
+        FROM [guacamole_entity]
+        WHERE
+            [guacamole_entity].name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier}
+                </foreach>
+            AND [guacamole_entity].type = 'USER_GROUP'
+            AND [guacamole_entity].entity_id NOT IN (
+                SELECT [guacamole_user_group_member].member_entity_id
+                FROM [guacamole_user_group_member]
+                WHERE [guacamole_user_group_member].user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            )
+    </insert>
+
+</mapper>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml
new file mode 100644
index 0000000..2c91c92
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserMapper.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserMapper" >
+
+    <!-- Select the username of all member users -->
+    <select id="selectChildIdentifiers" resultType="string">
+        SELECT name
+        FROM [guacamole_user_group_member]
+        JOIN [guacamole_entity] ON [guacamole_entity].entity_id = [guacamole_user_group_member].member_entity_id
+        WHERE
+            [guacamole_user_group_member].user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            AND [guacamole_entity].type = 'USER'
+    </select>
+
+    <!-- Select the usernames of all readable member users -->
+    <select id="selectReadableChildIdentifiers" resultType="string">
+        SELECT [guacamole_entity].name
+        FROM [guacamole_user_group_member]
+        JOIN [guacamole_entity] ON [guacamole_entity].entity_id = [guacamole_user_group_member].member_entity_id
+        JOIN [guacamole_user] ON [guacamole_user].entity_id = [guacamole_entity].entity_id
+        JOIN [guacamole_user_permission] ON affected_user_id = [guacamole_user].user_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_user_permission].entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND [guacamole_user_group_member].user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            AND [guacamole_entity].type = 'USER'
+            AND permission = 'READ'
+    </select>
+
+    <!-- Delete member users by name -->
+    <delete id="delete">
+        DELETE [guacamole_user_group_member]
+        FROM [guacamole_user_group_member]
+        JOIN [guacamole_entity] ON [guacamole_entity].entity_id = member_entity_id
+        WHERE
+            user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            AND [guacamole_entity].type = 'USER'
+            AND [guacamole_entity].name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+    </delete>
+
+    <!-- Insert member users by name -->
+    <insert id="insert">
+        INSERT INTO [guacamole_user_group_member] (
+            user_group_id,
+            member_entity_id
+        )
+        SELECT DISTINCT
+            #{parent.objectID,jdbcType=INTEGER},
+            [guacamole_entity].entity_id
+        FROM [guacamole_entity]
+        WHERE
+            [guacamole_entity].name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier}
+                </foreach>
+            AND [guacamole_entity].type = 'USER'
+            AND [guacamole_entity].entity_id NOT IN (
+                SELECT [guacamole_user_group_member].member_entity_id
+                FROM [guacamole_user_group_member]
+                WHERE [guacamole_user_group_member].user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            )
+    </insert>
+
+</mapper>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/ee356201/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml
new file mode 100644
index 0000000..0ea9252
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.usergroup.UserGroupParentUserGroupMapper" >
+
+    <!-- Select the names of all parent user groups -->
+    <select id="selectChildIdentifiers" resultType="string">
+        SELECT name
+        FROM [guacamole_user_group_member]
+        JOIN [guacamole_user_group] ON [guacamole_user_group_member].user_group_id = [guacamole_user_group].user_group_id
+        JOIN [guacamole_entity] ON [guacamole_entity].entity_id = [guacamole_user_group].entity_id
+        WHERE
+            [guacamole_user_group_member].member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            AND [guacamole_entity].type = 'USER_GROUP'
+    </select>
+
+    <!-- Select the names of all readable parent user groups -->
+    <select id="selectReadableChildIdentifiers" resultType="string">
+        SELECT [guacamole_entity].name
+        FROM [guacamole_user_group_member]
+        JOIN [guacamole_user_group] ON [guacamole_user_group_member].user_group_id = [guacamole_user_group].user_group_id
+        JOIN [guacamole_entity] ON [guacamole_entity].entity_id = [guacamole_user_group].entity_id
+        JOIN [guacamole_user_group_permission] ON affected_user_group_id = [guacamole_user_group].user_group_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="[guacamole_user_group_permission].entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND [guacamole_user_group_member].member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            AND [guacamole_entity].type = 'USER_GROUP'
+            AND permission = 'READ'
+    </select>
+
+    <!-- Delete parent groups by name -->
+    <delete id="delete">
+        DELETE [guacamole_user_group_member]
+        FROM [guacamole_user_group_member]
+        JOIN [guacamole_user_group] ON [guacamole_user_group].user_group_id = [guacamole_user_group_member].user_group_id
+        JOIN [guacamole_entity] ON [guacamole_entity].entity_id = [guacamole_user_group].entity_id
+        WHERE
+            member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            AND [guacamole_entity].type = 'USER_GROUP'
+            AND [guacamole_entity].name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+    </delete>
+
+    <!-- Insert parent groups by name -->
+    <insert id="insert">
+        INSERT INTO [guacamole_user_group_member] (
+            user_group_id,
+            member_entity_id
+        )
+        SELECT DISTINCT
+            [guacamole_user_group].user_group_id,
+            #{parent.entityID,jdbcType=INTEGER}
+        FROM [guacamole_user_group]
+        JOIN [guacamole_entity] ON [guacamole_user_group].entity_id = [guacamole_entity].entity_id
+        WHERE
+            [guacamole_entity].name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+            AND [guacamole_entity].type = 'USER_GROUP'
+            AND [guacamole_user_group].user_group_id NOT IN (
+                SELECT [guacamole_user_group_member].user_group_id
+                FROM [guacamole_user_group_member]
+                WHERE [guacamole_user_group_member].member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            )
+    </insert>
+
+</mapper>


[03/38] guacamole-client git commit: GUACAMOLE-220: Inherit from groups even if not determined by database.

Posted by vn...@apache.org.
http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
index ffca72d..37841de 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
@@ -69,12 +69,11 @@
         SELECT connection_group_id
         FROM guacamole_connection_group_permission
         WHERE
-            entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
     </select>
 
@@ -95,12 +94,11 @@
         WHERE
             <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer</if>
             <if test="parentIdentifier == null">parent_id IS NULL</if>
-            AND entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
     </select>
 
@@ -171,12 +169,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
         SELECT parent_id, guacamole_connection_group.connection_group_id
@@ -187,12 +184,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
         SELECT parent_id, guacamole_connection.connection_id
@@ -203,12 +199,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
         SELECT
@@ -222,12 +217,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
index a21b7d5..4ce168d 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
@@ -40,12 +40,11 @@
             connection_group_id
         FROM guacamole_connection_group_permission
         WHERE
-            entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="inherit"/>
-                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
 
     </select>
 
@@ -58,12 +57,11 @@
             connection_group_id
         FROM guacamole_connection_group_permission
         WHERE
-            entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="inherit"/>
-                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
             AND connection_group_id = #{identifier,jdbcType=INTEGER}::integer
 
@@ -75,12 +73,11 @@
         SELECT DISTINCT connection_group_id 
         FROM guacamole_connection_group_permission
         WHERE
-            entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="inherit"/>
-                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND connection_group_id IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
index 5d911de..68968d7 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
@@ -40,12 +40,11 @@
             connection_id
         FROM guacamole_connection_permission
         WHERE
-            entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="inherit"/>
-                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
 
     </select>
 
@@ -58,12 +57,11 @@
             connection_id
         FROM guacamole_connection_permission
         WHERE
-            entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="inherit"/>
-                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
             AND connection_id = #{identifier,jdbcType=INTEGER}::integer
 
@@ -75,12 +73,11 @@
         SELECT DISTINCT connection_id 
         FROM guacamole_connection_permission
         WHERE
-            entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="inherit"/>
-                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND connection_id IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
index 68b3032..4594c05 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
@@ -40,13 +40,11 @@
             sharing_profile_id
         FROM guacamole_sharing_profile_permission
         WHERE
-            entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="inherit"/>
-                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
-
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
 
     </select>
 
@@ -59,12 +57,11 @@
             sharing_profile_id
         FROM guacamole_sharing_profile_permission
         WHERE
-            entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="inherit"/>
-                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
             AND sharing_profile_id = #{identifier,jdbcType=INTEGER}::integer
 
@@ -76,12 +73,11 @@
         SELECT DISTINCT sharing_profile_id
         FROM guacamole_sharing_profile_permission
         WHERE
-            entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="inherit"/>
-                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND sharing_profile_id IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
index 25ebf97..ae86302 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
@@ -38,12 +38,11 @@
             permission
         FROM guacamole_system_permission
         WHERE
-            entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="inherit"/>
-                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
 
     </select>
 
@@ -55,12 +54,11 @@
             permission
         FROM guacamole_system_permission
         WHERE
-            entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="inherit"/>
-                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = #{type,jdbcType=VARCHAR}::guacamole_system_permission_type
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
index e5a844a..bd3ff93 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
@@ -42,12 +42,11 @@
         JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
         JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
         WHERE
-            guacamole_user_permission.entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="inherit"/>
-                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_permission.entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND affected_entity.type = 'USER'::guacamole_entity_type
 
     </select>
@@ -63,12 +62,11 @@
         JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
         JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
         WHERE
-            guacamole_user_permission.entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="inherit"/>
-                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_permission.entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
             AND affected_entity.name = #{identifier,jdbcType=VARCHAR}
             AND affected_entity.type = 'USER'::guacamole_entity_type
@@ -83,12 +81,11 @@
         JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
         JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
         WHERE
-            guacamole_user_permission.entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="inherit"/>
-                    <property name="entityID"    value="#{entity.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_permission.entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND affected_entity.name IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
index febf540..62548d7 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
@@ -52,12 +52,11 @@
         SELECT sharing_profile_id
         FROM guacamole_sharing_profile_permission
         WHERE
-            entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
     </select>
 
@@ -104,12 +103,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
         SELECT
@@ -123,12 +121,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
index 654351f..25d7659 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
@@ -70,16 +70,53 @@
         JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
         JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
         WHERE
-            guacamole_user_permission.entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND guacamole_entity.type = 'USER'::guacamole_entity_type
             AND permission = 'READ'
     </select>
 
+    <!-- Select names of all effective (including inherited) groups -->
+    <select id="selectEffectiveGroupIdentifiers" resultType="string">
+
+        WITH RECURSIVE related_entity(entity_id) AS (
+                SELECT
+                    guacamole_user_group.entity_id
+                FROM guacamole_user_group
+                JOIN guacamole_user_group_member ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
+                WHERE
+                    guacamole_user_group_member.member_entity_id = #{user.entityID}
+            <if test="!effectiveGroups.isEmpty()">
+                UNION
+                    SELECT
+                        guacamole_entity.entity_id
+                    FROM guacamole_entity
+                    WHERE
+                        type = 'USER_GROUP'::guacamole_entity_type
+                        AND name IN
+                            <foreach collection="effectiveGroups" item="effectiveGroup"
+                                     open="(" separator="," close=")">
+                                #{effectiveGroup,jdbcType=VARCHAR}
+                            </foreach>
+            </if>
+            UNION
+                SELECT
+                    guacamole_user_group.entity_id
+                FROM related_entity
+                JOIN guacamole_user_group_member ON related_entity.entity_id = guacamole_user_group_member.member_entity_id
+                JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
+        )
+        SELECT name
+        FROM related_entity
+        JOIN guacamole_entity ON related_entity.entity_id = guacamole_entity.entity_id
+        WHERE
+            guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type;
+
+    </select>
+
     <!-- Select multiple users by username -->
     <select id="select" resultMap="UserResultMap"
             resultSets="users,arbitraryAttributes">
@@ -163,12 +200,11 @@
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
             AND guacamole_entity.type = 'USER'::guacamole_entity_type
-            AND guacamole_user_permission.entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
         GROUP BY guacamole_user.user_id, guacamole_entity.entity_id;
 
@@ -186,12 +222,11 @@
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
             AND guacamole_entity.type = 'USER'::guacamole_entity_type
-            AND guacamole_user_permission.entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
index 862e2d7..6311a25 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
@@ -156,12 +156,11 @@
         <!-- Restrict to readable users -->
         JOIN guacamole_user_permission ON
                 guacamole_user_history.user_id       = guacamole_user_permission.affected_user_id
-            AND guacamole_user_permission.entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND guacamole_user_permission.permission = 'READ'
 
         <!-- Search terms -->


[17/38] guacamole-client git commit: GUACAMOLE-220: Map and allow manipulation of the user group members of user groups.

Posted by vn...@apache.org.
GUACAMOLE-220: Map and allow manipulation of the user group members of user groups.


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

Branch: refs/heads/master
Commit: 63be247db6ca3292afec9ecc532c3bd88d3a7ed0
Parents: ccd7920
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Apr 10 13:39:16 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:52 2018 -0700

----------------------------------------------------------------------
 .../jdbc/JDBCAuthenticationProviderModule.java  |  2 +
 .../auth/jdbc/usergroup/ModeledUserGroup.java   | 11 ++-
 .../UserGroupMemberUserGroupMapper.java         | 28 ++++++
 .../usergroup/UserGroupMemberUserGroupSet.java  | 57 ++++++++++++
 .../UserGroupMemberUserGroupMapper.xml          | 93 ++++++++++++++++++++
 5 files changed, 190 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/63be247d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
index 0750b10..ab7547f 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
@@ -85,6 +85,7 @@ import org.apache.guacamole.auth.jdbc.user.UserRecordMapper;
 import org.apache.guacamole.auth.jdbc.usergroup.ModeledUserGroup;
 import org.apache.guacamole.auth.jdbc.usergroup.UserGroupDirectory;
 import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMapper;
+import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserGroupMapper;
 import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserMapper;
 import org.apache.guacamole.auth.jdbc.usergroup.UserGroupService;
 import org.mybatis.guice.MyBatisModule;
@@ -137,6 +138,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
         addMapperClass(SharingProfileParameterMapper.class);
         addMapperClass(SharingProfilePermissionMapper.class);
         addMapperClass(UserGroupMapper.class);
+        addMapperClass(UserGroupMemberUserGroupMapper.class);
         addMapperClass(UserGroupMemberUserMapper.class);
         addMapperClass(UserGroupPermissionMapper.class);
         addMapperClass(UserMapper.class);

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/63be247d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
index 3612eea..fcf1250 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
@@ -82,6 +82,13 @@ public class ModeledUserGroup extends ModeledPermissions<UserGroupModel>
     private Provider<UserGroupMemberUserSet> memberUserSetProvider;
 
     /**
+     * Provider for RelatedObjectSets containing the user groups that are
+     * members of this user group.
+     */
+    @Inject
+    private Provider<UserGroupMemberUserGroupSet> memberUserGroupSetProvider;
+
+    /**
      * Whether attributes which control access restrictions should be exposed
      * via getAttributes() or allowed to be set via setAttributes().
      */
@@ -189,7 +196,9 @@ public class ModeledUserGroup extends ModeledPermissions<UserGroupModel>
 
     @Override
     public RelatedObjectSet getMemberUserGroups() throws GuacamoleException {
-        return new SimpleRelatedObjectSet();
+        UserGroupMemberUserGroupSet memberUserGroupSet = memberUserGroupSetProvider.get();
+        memberUserGroupSet.init(getCurrentUser(), this);
+        return memberUserGroupSet;
     }
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/63be247d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.java
new file mode 100644
index 0000000..70baef7
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.java
@@ -0,0 +1,28 @@
+/*
+ * 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.usergroup;
+
+import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper;
+
+/**
+ * Mapper for the one-to-many relationship between a user group and its user
+ * group members.
+ */
+public interface UserGroupMemberUserGroupMapper extends ObjectRelationMapper<UserGroupModel> {}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/63be247d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupSet.java
new file mode 100644
index 0000000..9684a47
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupSet.java
@@ -0,0 +1,57 @@
+/*
+ * 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.usergroup;
+
+import com.google.inject.Inject;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper;
+import org.apache.guacamole.auth.jdbc.base.RelatedObjectSet;
+import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
+
+/**
+ * RelatedObjectSet implementation which represents the one-to-many
+ * relationship between a particular user group and its user group members.
+ */
+public class UserGroupMemberUserGroupSet extends RelatedObjectSet<ModeledUserGroup, UserGroupModel> {
+
+    /**
+     * Mapper for the relation between user groups and their user group members.
+     */
+    @Inject
+    private UserGroupMemberUserGroupMapper userGroupMemberUserGroupMapper;
+
+    @Override
+    protected ObjectRelationMapper<UserGroupModel> getObjectRelationMapper() {
+        return userGroupMemberUserGroupMapper;
+    }
+
+    @Override
+    protected ObjectPermissionSet
+        getParentObjectEffectivePermissionSet() throws GuacamoleException {
+        return getCurrentUser().getUser().getEffectivePermissions().getUserGroupPermissions();
+    }
+
+    @Override
+    protected ObjectPermissionSet getChildObjectEffectivePermissionSet()
+            throws GuacamoleException {
+        return getCurrentUser().getUser().getEffectivePermissions().getUserGroupPermissions();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/63be247d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml
new file mode 100644
index 0000000..13f4d71
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupMemberUserGroupMapper.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserGroupMapper" >
+
+    <!-- Select the names of all member user groups -->
+    <select id="selectChildIdentifiers" resultType="string">
+        SELECT name
+        FROM guacamole_user_group_member
+        JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group_member.member_entity_id
+        WHERE
+            guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type
+    </select>
+
+    <!-- Select the names of all readable member user groups -->
+    <select id="selectReadableChildIdentifiers" resultType="string">
+        SELECT guacamole_entity.name
+        FROM guacamole_user_group_member
+        JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group_member.member_entity_id
+        JOIN guacamole_user_group ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        JOIN guacamole_user_group_permission ON affected_user_group_id = guacamole_user_group.user_group_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_group_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type
+            AND permission = 'READ'
+    </select>
+
+    <!-- Delete member groups by name -->
+    <delete id="delete">
+        DELETE FROM guacamole_user_group_member
+        USING guacamole_entity
+        WHERE
+            user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            AND guacamole_entity.entity_id = member_entity_id
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type
+            AND guacamole_entity.name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+    </delete>
+
+    <!-- Insert member groups by name -->
+    <insert id="insert">
+        INSERT INTO guacamole_user_group_member (
+            user_group_id,
+            member_entity_id
+        )
+        SELECT DISTINCT
+            #{parent.objectID,jdbcType=INTEGER},
+            guacamole_entity.entity_id
+        FROM guacamole_entity
+        WHERE
+            guacamole_entity.name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier}
+                </foreach>
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type
+            AND guacamole_entity.entity_id NOT IN (
+                SELECT guacamole_user_group_member.member_entity_id
+                FROM guacamole_user_group_member
+                WHERE guacamole_user_group_member.user_group_id = #{parent.objectID,jdbcType=INTEGER}
+            )
+    </insert>
+
+</mapper>


[22/38] guacamole-client git commit: GUACAMOLE-220: Map and allow manipulation of the user group parents of user groups.

Posted by vn...@apache.org.
GUACAMOLE-220: Map and allow manipulation of the user group parents of user groups.


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

Branch: refs/heads/master
Commit: 856ab44373df4e6b458c3c9c63536afb17af265e
Parents: 63be247
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Apr 10 14:31:13 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:52 2018 -0700

----------------------------------------------------------------------
 .../jdbc/JDBCAuthenticationProviderModule.java  |  2 +
 .../auth/jdbc/usergroup/ModeledUserGroup.java   | 12 ++-
 .../UserGroupParentUserGroupMapper.java         | 28 ++++++
 .../usergroup/UserGroupParentUserGroupSet.java  | 58 ++++++++++++
 .../UserGroupParentUserGroupMapper.xml          | 96 ++++++++++++++++++++
 5 files changed, 194 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/856ab443/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
index ab7547f..2d4c67a 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
@@ -87,6 +87,7 @@ import org.apache.guacamole.auth.jdbc.usergroup.UserGroupDirectory;
 import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMapper;
 import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserGroupMapper;
 import org.apache.guacamole.auth.jdbc.usergroup.UserGroupMemberUserMapper;
+import org.apache.guacamole.auth.jdbc.usergroup.UserGroupParentUserGroupMapper;
 import org.apache.guacamole.auth.jdbc.usergroup.UserGroupService;
 import org.mybatis.guice.MyBatisModule;
 import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider;
@@ -140,6 +141,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
         addMapperClass(UserGroupMapper.class);
         addMapperClass(UserGroupMemberUserGroupMapper.class);
         addMapperClass(UserGroupMemberUserMapper.class);
+        addMapperClass(UserGroupParentUserGroupMapper.class);
         addMapperClass(UserGroupPermissionMapper.class);
         addMapperClass(UserMapper.class);
         addMapperClass(UserPermissionMapper.class);

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/856ab443/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
index fcf1250..914a292 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
@@ -35,7 +35,6 @@ import org.apache.guacamole.form.Field;
 import org.apache.guacamole.form.Form;
 import org.apache.guacamole.net.auth.RelatedObjectSet;
 import org.apache.guacamole.net.auth.UserGroup;
-import org.apache.guacamole.net.auth.simple.SimpleRelatedObjectSet;
 
 /**
  * An implementation of the UserGroup object which is backed by a database model.
@@ -75,6 +74,13 @@ public class ModeledUserGroup extends ModeledPermissions<UserGroupModel>
             )));
 
     /**
+     * Provider for RelatedObjectSets containing the user groups of which this
+     * user group is a member.
+     */
+    @Inject
+    private Provider<UserGroupParentUserGroupSet> parentUserGroupSetProvider;
+
+    /**
      * Provider for RelatedObjectSets containing the users that are members of
      * this user group.
      */
@@ -184,7 +190,9 @@ public class ModeledUserGroup extends ModeledPermissions<UserGroupModel>
 
     @Override
     public RelatedObjectSet getUserGroups() throws GuacamoleException {
-        return new SimpleRelatedObjectSet();
+        UserGroupParentUserGroupSet parentUserGroupSet = parentUserGroupSetProvider.get();
+        parentUserGroupSet.init(getCurrentUser(), this);
+        return parentUserGroupSet;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/856ab443/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.java
new file mode 100644
index 0000000..37433cc
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.java
@@ -0,0 +1,28 @@
+/*
+ * 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.usergroup;
+
+import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper;
+
+/**
+ * Mapper for the one-to-many relationship between a user group and its
+ * containing user groups.
+ */
+public interface UserGroupParentUserGroupMapper extends ObjectRelationMapper<UserGroupModel> {}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/856ab443/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupSet.java
new file mode 100644
index 0000000..ee1f8ef
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupSet.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.usergroup;
+
+import com.google.inject.Inject;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.base.ObjectRelationMapper;
+import org.apache.guacamole.auth.jdbc.base.RelatedObjectSet;
+import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
+
+/**
+ * RelatedObjectSet implementation which represents the one-to-many
+ * relationship between a particular user group and its containing user groups.
+ */
+public class UserGroupParentUserGroupSet extends RelatedObjectSet<ModeledUserGroup, UserGroupModel> {
+
+    /**
+     * Mapper for the relation between user groups and their containing user
+     * groups.
+     */
+    @Inject
+    private UserGroupParentUserGroupMapper userGroupParentUserGroupMapper;
+
+    @Override
+    protected ObjectRelationMapper<UserGroupModel> getObjectRelationMapper() {
+        return userGroupParentUserGroupMapper;
+    }
+
+    @Override
+    protected ObjectPermissionSet
+        getParentObjectEffectivePermissionSet() throws GuacamoleException {
+        return getCurrentUser().getUser().getEffectivePermissions().getUserGroupPermissions();
+    }
+
+    @Override
+    protected ObjectPermissionSet getChildObjectEffectivePermissionSet()
+            throws GuacamoleException {
+        return getCurrentUser().getUser().getEffectivePermissions().getUserGroupPermissions();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/856ab443/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml
new file mode 100644
index 0000000..035211c
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/usergroup/UserGroupParentUserGroupMapper.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.usergroup.UserGroupParentUserGroupMapper" >
+
+    <!-- Select the names of all parent user groups -->
+    <select id="selectChildIdentifiers" resultType="string">
+        SELECT name
+        FROM guacamole_user_group_member
+        JOIN guacamole_user_group ON guacamole_user_group_member.user_group_id = guacamole_user_group.user_group_id
+        JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group.entity_id
+        WHERE
+            guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type
+    </select>
+
+    <!-- Select the names of all readable parent user groups -->
+    <select id="selectReadableChildIdentifiers" resultType="string">
+        SELECT guacamole_entity.name
+        FROM guacamole_user_group_member
+        JOIN guacamole_user_group ON guacamole_user_group_member.user_group_id = guacamole_user_group.user_group_id
+        JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group.entity_id
+        JOIN guacamole_user_group_permission ON affected_user_group_id = guacamole_user_group.user_group_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_group_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type
+            AND permission = 'READ'
+    </select>
+
+    <!-- Delete parent groups by name -->
+    <delete id="delete">
+        DELETE FROM guacamole_user_group_member
+        USING guacamole_user_group, guacamole_entity
+        WHERE
+            member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            AND guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
+            AND guacamole_entity.entity_id = guacamole_user_group.entity_id
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type
+            AND guacamole_entity.name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+    </delete>
+
+    <!-- Insert parent groups by name -->
+    <insert id="insert">
+        INSERT INTO guacamole_user_group_member (
+            user_group_id,
+            member_entity_id
+        )
+        SELECT DISTINCT
+            guacamole_user_group.user_group_id,
+            #{parent.entityID,jdbcType=INTEGER}
+        FROM guacamole_user_group
+        JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        WHERE
+            guacamole_entity.name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+            AND guacamole_entity.type = 'USER_GROUP'::guacamole_entity_type
+            AND guacamole_user_group.user_group_id NOT IN (
+                SELECT guacamole_user_group_member.user_group_id
+                FROM guacamole_user_group_member
+                WHERE guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            )
+    </insert>
+
+</mapper>


[15/38] guacamole-client git commit: GUACAMOLE-220: Add MySQL and SQL Server versions of user group schema.

Posted by vn...@apache.org.
GUACAMOLE-220: Add MySQL and SQL Server versions of user group schema.


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

Branch: refs/heads/master
Commit: 1d0fcc1732fded614707b0e425af89eca0526e6a
Parents: 78d5e3b
Author: Michael Jumper <mj...@apache.org>
Authored: Fri Sep 7 20:49:13 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:52 2018 -0700

----------------------------------------------------------------------
 .../schema/001-create-schema.sql                | 196 +++++--
 .../schema/002-create-admin-user.sql            |  26 +-
 .../schema/upgrade/upgrade-pre-1.0.0.sql        | 335 ++++++++++++
 .../schema/001-create-schema.sql                | 303 ++++++++---
 .../schema/002-create-admin-user.sql            |  21 +-
 .../schema/upgrade/upgrade-pre-1.0.0.sql        | 532 +++++++++++++++++++
 6 files changed, 1294 insertions(+), 119 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/1d0fcc17/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql
index 76711f1..1606af1 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql
@@ -79,6 +79,25 @@ CREATE TABLE `guacamole_connection` (
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 --
+-- Table of base entities which may each be either a user or user group. Other
+-- tables which represent qualities shared by both users and groups will point
+-- to guacamole_entity, while tables which represent qualities specific to
+-- users or groups will point to guacamole_user or guacamole_user_group.
+--
+
+CREATE TABLE `guacamole_entity` (
+
+  `entity_id`     int(11)            NOT NULL AUTO_INCREMENT,
+  `name`          varchar(128)       NOT NULL,
+  `type`          enum('USER',
+                       'USER_GROUP') NOT NULL,
+
+  PRIMARY KEY (`entity_id`),
+  UNIQUE KEY `guacamole_entity_name_scope` (`type`, `name`)
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
 -- Table of users. Each user has a unique username and a hashed password
 -- with corresponding salt. Although the authentication system will always set
 -- salted passwords, other systems may set unsalted passwords by simply not
@@ -88,9 +107,9 @@ CREATE TABLE `guacamole_connection` (
 CREATE TABLE `guacamole_user` (
 
   `user_id`       int(11)      NOT NULL AUTO_INCREMENT,
+  `entity_id`     int(11)      NOT NULL,
 
-  -- Username and optionally-salted password
-  `username`      varchar(128) NOT NULL,
+  -- Optionally-salted password
   `password_hash` binary(32)   NOT NULL,
   `password_salt` binary(32),
   `password_date` datetime     NOT NULL,
@@ -117,7 +136,61 @@ CREATE TABLE `guacamole_user` (
   `organizational_role` VARCHAR(256),
 
   PRIMARY KEY (`user_id`),
-  UNIQUE KEY `username` (`username`)
+
+  UNIQUE KEY `guacamole_user_single_entity` (`entity_id`),
+
+  CONSTRAINT `guacamole_user_entity`
+    FOREIGN KEY (`entity_id`)
+    REFERENCES `guacamole_entity` (`entity_id`)
+    ON DELETE CASCADE
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Table of user groups. Each user group may have an arbitrary set of member
+-- users and member groups, with those members inheriting the permissions
+-- granted to that group.
+--
+
+CREATE TABLE `guacamole_user_group` (
+
+  `user_group_id` int(11)      NOT NULL AUTO_INCREMENT,
+  `entity_id`     int(11)      NOT NULL,
+
+  -- Group disabled status
+  `disabled`      boolean      NOT NULL DEFAULT 0,
+
+  PRIMARY KEY (`user_group_id`),
+
+  UNIQUE KEY `guacamole_user_group_single_entity` (`entity_id`),
+
+  CONSTRAINT `guacamole_user_group_entity`
+    FOREIGN KEY (`entity_id`)
+    REFERENCES `guacamole_entity` (`entity_id`)
+    ON DELETE CASCADE
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Table of users which are members of given user groups.
+--
+
+CREATE TABLE `guacamole_user_group_member` (
+
+  `user_group_id`    int(11)     NOT NULL,
+  `member_entity_id` int(11)     NOT NULL,
+
+  PRIMARY KEY (`user_group_id`, `member_entity_id`),
+
+  -- Parent must be a user group
+  CONSTRAINT `guacamole_user_group_member_parent_id`
+    FOREIGN KEY (`user_group_id`)
+    REFERENCES `guacamole_user_group` (`user_group_id`) ON DELETE CASCADE,
+
+  -- Member may be either a user or a user group (any entity)
+  CONSTRAINT `guacamole_user_group_member_entity_id`
+    FOREIGN KEY (`member_entity_id`)
+    REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
 
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
@@ -208,6 +281,28 @@ CREATE TABLE guacamole_user_attribute (
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 --
+-- Table of arbitrary user group attributes. Each attribute is simply a
+-- name/value pair associated with a user group. Arbitrary attributes are
+-- defined by other extensions. Attributes defined by this extension will be
+-- mapped to properly-typed columns of a specific table.
+--
+
+CREATE TABLE guacamole_user_group_attribute (
+
+  `user_group_id`   int(11)       NOT NULL,
+  `attribute_name`  varchar(128)  NOT NULL,
+  `attribute_value` varchar(4096) NOT NULL,
+
+  PRIMARY KEY (`user_group_id`, `attribute_name`),
+  KEY `user_group_id` (`user_group_id`),
+
+  CONSTRAINT `guacamole_user_group_attribute_ibfk_1`
+    FOREIGN KEY (`user_group_id`)
+    REFERENCES `guacamole_user_group` (`user_group_id`) ON DELETE CASCADE
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
 -- Table of arbitrary connection attributes. Each attribute is simply a
 -- name/value pair associated with a connection. Arbitrary attributes are
 -- defined by other extensions. Attributes defined by this extension will be
@@ -274,128 +369,157 @@ CREATE TABLE guacamole_sharing_profile_attribute (
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 --
--- Table of connection permissions. Each connection permission grants a user
--- specific access to a connection.
+-- Table of connection permissions. Each connection permission grants a user or
+-- user group specific access to a connection.
 --
 
 CREATE TABLE `guacamole_connection_permission` (
 
-  `user_id`       int(11) NOT NULL,
+  `entity_id`     int(11) NOT NULL,
   `connection_id` int(11) NOT NULL,
   `permission`    enum('READ',
                        'UPDATE',
                        'DELETE',
                        'ADMINISTER') NOT NULL,
 
-  PRIMARY KEY (`user_id`,`connection_id`,`permission`),
+  PRIMARY KEY (`entity_id`,`connection_id`,`permission`),
 
   CONSTRAINT `guacamole_connection_permission_ibfk_1`
     FOREIGN KEY (`connection_id`)
     REFERENCES `guacamole_connection` (`connection_id`) ON DELETE CASCADE,
 
-  CONSTRAINT `guacamole_connection_permission_ibfk_2`
-    FOREIGN KEY (`user_id`)
-    REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE
+  CONSTRAINT `guacamole_connection_permission_entity`
+    FOREIGN KEY (`entity_id`)
+    REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
 
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 --
 -- Table of connection group permissions. Each group permission grants a user
--- specific access to a connection group.
+-- or user group specific access to a connection group.
 --
 
 CREATE TABLE `guacamole_connection_group_permission` (
 
-  `user_id`             int(11) NOT NULL,
+  `entity_id`           int(11) NOT NULL,
   `connection_group_id` int(11) NOT NULL,
   `permission`          enum('READ',
                              'UPDATE',
                              'DELETE',
                              'ADMINISTER') NOT NULL,
 
-  PRIMARY KEY (`user_id`,`connection_group_id`,`permission`),
+  PRIMARY KEY (`entity_id`,`connection_group_id`,`permission`),
 
   CONSTRAINT `guacamole_connection_group_permission_ibfk_1`
     FOREIGN KEY (`connection_group_id`)
     REFERENCES `guacamole_connection_group` (`connection_group_id`) ON DELETE CASCADE,
 
-  CONSTRAINT `guacamole_connection_group_permission_ibfk_2`
-    FOREIGN KEY (`user_id`)
-    REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE
+  CONSTRAINT `guacamole_connection_group_permission_entity`
+    FOREIGN KEY (`entity_id`)
+    REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
 
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 --
 -- Table of sharing profile permissions. Each sharing profile permission grants
--- a user specific access to a sharing profile.
+-- a user or user group specific access to a sharing profile.
 --
 
 CREATE TABLE guacamole_sharing_profile_permission (
 
-  `user_id`            integer NOT NULL,
+  `entity_id`          integer NOT NULL,
   `sharing_profile_id` integer NOT NULL,
   `permission`         enum('READ',
                             'UPDATE',
                             'DELETE',
                             'ADMINISTER') NOT NULL,
 
-  PRIMARY KEY (`user_id`, `sharing_profile_id`, `permission`),
+  PRIMARY KEY (`entity_id`, `sharing_profile_id`, `permission`),
 
   CONSTRAINT `guacamole_sharing_profile_permission_ibfk_1`
     FOREIGN KEY (`sharing_profile_id`)
     REFERENCES `guacamole_sharing_profile` (`sharing_profile_id`) ON DELETE CASCADE,
 
-  CONSTRAINT `guacamole_sharing_profile_permission_ibfk_2`
-    FOREIGN KEY (`user_id`)
-    REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE
+  CONSTRAINT `guacamole_sharing_profile_permission_entity`
+    FOREIGN KEY (`entity_id`)
+    REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
 
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 --
--- Table of system permissions. Each system permission grants a user a
--- system-level privilege of some kind.
+-- Table of system permissions. Each system permission grants a user or user
+-- group a system-level privilege of some kind.
 --
 
 CREATE TABLE `guacamole_system_permission` (
 
-  `user_id`    int(11) NOT NULL,
+  `entity_id`  int(11) NOT NULL,
   `permission` enum('CREATE_CONNECTION',
                     'CREATE_CONNECTION_GROUP',
                     'CREATE_SHARING_PROFILE',
                     'CREATE_USER',
+                    'CREATE_USER_GROUP',
                     'ADMINISTER') NOT NULL,
 
-  PRIMARY KEY (`user_id`,`permission`),
+  PRIMARY KEY (`entity_id`,`permission`),
 
-  CONSTRAINT `guacamole_system_permission_ibfk_1`
-    FOREIGN KEY (`user_id`)
-    REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE
+  CONSTRAINT `guacamole_system_permission_entity`
+    FOREIGN KEY (`entity_id`)
+    REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
 
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 --
--- Table of user permissions. Each user permission grants a user access to
--- another user (the "affected" user) for a specific type of operation.
+-- Table of user permissions. Each user permission grants a user or user group
+-- access to another user (the "affected" user) for a specific type of
+-- operation.
 --
 
 CREATE TABLE `guacamole_user_permission` (
 
-  `user_id`          int(11) NOT NULL,
+  `entity_id`        int(11) NOT NULL,
   `affected_user_id` int(11) NOT NULL,
   `permission`       enum('READ',
                           'UPDATE',
                           'DELETE',
                           'ADMINISTER') NOT NULL,
 
-  PRIMARY KEY (`user_id`,`affected_user_id`,`permission`),
+  PRIMARY KEY (`entity_id`,`affected_user_id`,`permission`),
 
   CONSTRAINT `guacamole_user_permission_ibfk_1`
     FOREIGN KEY (`affected_user_id`)
     REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE,
 
-  CONSTRAINT `guacamole_user_permission_ibfk_2`
-    FOREIGN KEY (`user_id`)
-    REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE
+  CONSTRAINT `guacamole_user_permission_entity`
+    FOREIGN KEY (`entity_id`)
+    REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Table of user group permissions. Each user group permission grants a user
+-- or user group access to a another user group (the "affected" user group) for
+-- a specific type of operation.
+--
+
+CREATE TABLE `guacamole_user_group_permission` (
+
+  `entity_id`              int(11) NOT NULL,
+  `affected_user_group_id` int(11) NOT NULL,
+  `permission`             enum('READ',
+                                'UPDATE',
+                                'DELETE',
+                                'ADMINISTER') NOT NULL,
+
+  PRIMARY KEY (`entity_id`, `affected_user_group_id`, `permission`),
+
+  CONSTRAINT `guacamole_user_group_permission_affected_user_group`
+    FOREIGN KEY (`affected_user_group_id`)
+    REFERENCES `guacamole_user_group` (`user_group_id`) ON DELETE CASCADE,
+
+  CONSTRAINT `guacamole_user_group_permission_entity`
+    FOREIGN KEY (`entity_id`)
+    REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
 
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/1d0fcc17/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/002-create-admin-user.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/002-create-admin-user.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/002-create-admin-user.sql
index cfc8313..f62d6d1 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/002-create-admin-user.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/002-create-admin-user.sql
@@ -18,32 +18,36 @@
 --
 
 -- Create default user "guacadmin" with password "guacadmin"
-INSERT INTO guacamole_user (username, password_hash, password_salt, password_date)
-VALUES ('guacadmin',
+INSERT INTO guacamole_entity (name, type) VALUES ('guacadmin', 'USER');
+INSERT INTO guacamole_user (entity_id, password_hash, password_salt, password_date)
+SELECT
+    entity_id,
     x'CA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960',  -- 'guacadmin'
     x'FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264',
-    NOW());
+    NOW()
+FROM guacamole_entity WHERE name = 'guacadmin';
 
 -- Grant this user all system permissions
-INSERT INTO guacamole_system_permission
-SELECT user_id, permission
+INSERT INTO guacamole_system_permission (entity_id, permission)
+SELECT entity_id, permission
 FROM (
           SELECT 'guacadmin'  AS username, 'CREATE_CONNECTION'       AS permission
     UNION SELECT 'guacadmin'  AS username, 'CREATE_CONNECTION_GROUP' AS permission
     UNION SELECT 'guacadmin'  AS username, 'CREATE_SHARING_PROFILE'  AS permission
     UNION SELECT 'guacadmin'  AS username, 'CREATE_USER'             AS permission
+    UNION SELECT 'guacadmin'  AS username, 'CREATE_USER_GROUP'       AS permission
     UNION SELECT 'guacadmin'  AS username, 'ADMINISTER'              AS permission
 ) permissions
-JOIN guacamole_user ON permissions.username = guacamole_user.username;
+JOIN guacamole_entity ON permissions.username = guacamole_entity.name AND guacamole_entity.type = 'USER';
 
 -- Grant admin permission to read/update/administer self
-INSERT INTO guacamole_user_permission
-SELECT guacamole_user.user_id, affected.user_id, permission
+INSERT INTO guacamole_user_permission (entity_id, affected_user_id, permission)
+SELECT guacamole_entity.entity_id, guacamole_user.user_id, permission
 FROM (
           SELECT 'guacadmin' AS username, 'guacadmin' AS affected_username, 'READ'       AS permission
     UNION SELECT 'guacadmin' AS username, 'guacadmin' AS affected_username, 'UPDATE'     AS permission
     UNION SELECT 'guacadmin' AS username, 'guacadmin' AS affected_username, 'ADMINISTER' AS permission
 ) permissions
-JOIN guacamole_user          ON permissions.username = guacamole_user.username
-JOIN guacamole_user affected ON permissions.affected_username = affected.username;
-
+JOIN guacamole_entity          ON permissions.username = guacamole_entity.name AND guacamole_entity.type = 'USER'
+JOIN guacamole_entity affected ON permissions.affected_username = affected.name AND guacamole_entity.type = 'USER'
+JOIN guacamole_user            ON guacamole_user.entity_id = affected.entity_id;

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/1d0fcc17/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.0.0.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.0.0.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.0.0.sql
index 2979f53..8332d7f 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.0.0.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.0.0.sql
@@ -18,6 +18,319 @@
 --
 
 --
+-- Add new system-level permission
+--
+
+ALTER TABLE `guacamole_system_permission`
+    MODIFY `permission` enum('CREATE_CONNECTION',
+                             'CREATE_CONNECTION_GROUP',
+                             'CREATE_SHARING_PROFILE',
+                             'CREATE_USER',
+                             'CREATE_USER_GROUP',
+                             'ADMINISTER') NOT NULL;
+
+--
+-- Table of base entities which may each be either a user or user group. Other
+-- tables which represent qualities shared by both users and groups will point
+-- to guacamole_entity, while tables which represent qualities specific to
+-- users or groups will point to guacamole_user or guacamole_user_group.
+--
+
+CREATE TABLE `guacamole_entity` (
+
+  `entity_id`     int(11)            NOT NULL AUTO_INCREMENT,
+  `name`          varchar(128)       NOT NULL,
+  `type`          enum('USER',
+                       'USER_GROUP') NOT NULL,
+
+  PRIMARY KEY (`entity_id`),
+  UNIQUE KEY `guacamole_entity_name_scope` (`type`, `name`)
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Table of user groups. Each user group may have an arbitrary set of member
+-- users and member groups, with those members inheriting the permissions
+-- granted to that group.
+--
+
+CREATE TABLE `guacamole_user_group` (
+
+  `user_group_id` int(11)      NOT NULL AUTO_INCREMENT,
+  `entity_id`     int(11)      NOT NULL,
+
+  -- Group disabled status
+  `disabled`      boolean      NOT NULL DEFAULT 0,
+
+  PRIMARY KEY (`user_group_id`),
+
+  UNIQUE KEY `guacamole_user_group_single_entity` (`entity_id`),
+
+  CONSTRAINT `guacamole_user_group_entity`
+    FOREIGN KEY (`entity_id`)
+    REFERENCES `guacamole_entity` (`entity_id`)
+    ON DELETE CASCADE
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Table of users which are members of given user groups.
+--
+
+CREATE TABLE `guacamole_user_group_member` (
+
+  `user_group_id`    int(11)     NOT NULL,
+  `member_entity_id` int(11)     NOT NULL,
+
+  PRIMARY KEY (`user_group_id`, `member_entity_id`),
+
+  -- Parent must be a user group
+  CONSTRAINT `guacamole_user_group_member_parent_id`
+    FOREIGN KEY (`user_group_id`)
+    REFERENCES `guacamole_user_group` (`user_group_id`) ON DELETE CASCADE,
+
+  -- Member may be either a user or a user group (any entity)
+  CONSTRAINT `guacamole_user_group_member_entity_id`
+    FOREIGN KEY (`member_entity_id`)
+    REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Table of user group permissions. Each user group permission grants a user
+-- or user group access to a another user group (the "affected" user group) for
+-- a specific type of operation.
+--
+
+CREATE TABLE `guacamole_user_group_permission` (
+
+  `entity_id`              int(11) NOT NULL,
+  `affected_user_group_id` int(11) NOT NULL,
+  `permission`             enum('READ',
+                                'UPDATE',
+                                'DELETE',
+                                'ADMINISTER') NOT NULL,
+
+  PRIMARY KEY (`entity_id`, `affected_user_group_id`, `permission`),
+
+  CONSTRAINT `guacamole_user_group_permission_affected_user_group`
+    FOREIGN KEY (`affected_user_group_id`)
+    REFERENCES `guacamole_user_group` (`user_group_id`) ON DELETE CASCADE,
+
+  CONSTRAINT `guacamole_user_group_permission_entity`
+    FOREIGN KEY (`entity_id`)
+    REFERENCES `guacamole_entity` (`entity_id`) ON DELETE CASCADE
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Modify guacamole_user table to use guacamole_entity as a base
+--
+
+-- Add new entity_id column
+ALTER TABLE guacamole_user ADD COLUMN entity_id int(11);
+
+-- Create user entities for each guacamole_user entry
+INSERT INTO guacamole_entity (name, type)
+SELECT username, 'USER' FROM guacamole_user;
+
+-- Update guacamole_user to point to corresponding guacamole_entity
+UPDATE guacamole_user SET entity_id = (
+    SELECT entity_id FROM guacamole_entity
+    WHERE
+            username = guacamole_entity.name
+        AND type = 'USER'
+);
+
+-- The entity_id column should now be safely non-NULL
+ALTER TABLE guacamole_user MODIFY entity_id int(11) NOT NULL;
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE guacamole_user
+    ADD CONSTRAINT guacamole_user_single_entity
+    UNIQUE (entity_id);
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE guacamole_user
+    ADD CONSTRAINT guacamole_user_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id)
+    ON DELETE CASCADE;
+
+-- The username column can now safely be removed
+ALTER TABLE guacamole_user DROP COLUMN username;
+
+--
+-- Modify guacamole_connection_permission to use guacamole_entity instead of
+-- guacamole_user
+--
+
+-- Add new entity_id column
+ALTER TABLE guacamole_connection_permission ADD COLUMN entity_id int(11);
+
+-- Update guacamole_connection_permission to point to the guacamole_entity
+-- that has been granted the permission
+UPDATE guacamole_connection_permission SET entity_id = (
+    SELECT entity_id FROM guacamole_user
+    WHERE guacamole_user.user_id = guacamole_connection_permission.user_id
+);
+
+-- The entity_id column should now be safely non-NULL
+ALTER TABLE guacamole_connection_permission MODIFY entity_id int(11) NOT NULL;
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE guacamole_connection_permission
+    ADD CONSTRAINT guacamole_connection_permission_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id)
+    ON DELETE CASCADE;
+
+-- Remove user_id column
+ALTER TABLE guacamole_connection_permission DROP FOREIGN KEY guacamole_connection_permission_ibfk_2;
+ALTER TABLE guacamole_connection_permission DROP PRIMARY KEY;
+ALTER TABLE guacamole_connection_permission DROP COLUMN user_id;
+
+-- Add new primary key which uses entity_id
+ALTER TABLE guacamole_connection_permission
+    ADD PRIMARY KEY (entity_id, connection_id, permission);
+
+--
+-- Modify guacamole_connection_group_permission to use guacamole_entity instead
+-- of guacamole_user
+--
+
+-- Add new entity_id column
+ALTER TABLE guacamole_connection_group_permission ADD COLUMN entity_id int(11);
+
+-- Update guacamole_connection_group_permission to point to the guacamole_entity
+-- that has been granted the permission
+UPDATE guacamole_connection_group_permission SET entity_id = (
+    SELECT entity_id FROM guacamole_user
+    WHERE guacamole_user.user_id = guacamole_connection_group_permission.user_id
+);
+
+-- The entity_id column should now be safely non-NULL
+ALTER TABLE guacamole_connection_group_permission MODIFY entity_id int(11) NOT NULL;
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE guacamole_connection_group_permission
+    ADD CONSTRAINT guacamole_connection_group_permission_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id)
+    ON DELETE CASCADE;
+
+-- Remove user_id column
+ALTER TABLE guacamole_connection_group_permission DROP FOREIGN KEY guacamole_connection_group_permission_ibfk_2;
+ALTER TABLE guacamole_connection_group_permission DROP PRIMARY KEY;
+ALTER TABLE guacamole_connection_group_permission DROP COLUMN user_id;
+
+-- Add new primary key which uses entity_id
+ALTER TABLE guacamole_connection_group_permission
+    ADD PRIMARY KEY (entity_id, connection_group_id, permission);
+
+--
+-- Modify guacamole_sharing_profile_permission to use guacamole_entity instead
+-- of guacamole_user
+--
+
+-- Add new entity_id column
+ALTER TABLE guacamole_sharing_profile_permission ADD COLUMN entity_id int(11);
+
+-- Update guacamole_sharing_profile_permission to point to the guacamole_entity
+-- that has been granted the permission
+UPDATE guacamole_sharing_profile_permission SET entity_id = (
+    SELECT entity_id FROM guacamole_user
+    WHERE guacamole_user.user_id = guacamole_sharing_profile_permission.user_id
+);
+
+-- The entity_id column should now be safely non-NULL
+ALTER TABLE guacamole_sharing_profile_permission MODIFY entity_id int(11) NOT NULL;
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE guacamole_sharing_profile_permission
+    ADD CONSTRAINT guacamole_sharing_profile_permission_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id)
+    ON DELETE CASCADE;
+
+-- Remove user_id column
+ALTER TABLE guacamole_sharing_profile_permission DROP FOREIGN KEY guacamole_sharing_profile_permission_ibfk_2;
+ALTER TABLE guacamole_sharing_profile_permission DROP PRIMARY KEY;
+ALTER TABLE guacamole_sharing_profile_permission DROP COLUMN user_id;
+
+-- Add new primary key which uses entity_id
+ALTER TABLE guacamole_sharing_profile_permission
+    ADD PRIMARY KEY (entity_id, sharing_profile_id, permission);
+
+--
+-- Modify guacamole_user_permission to use guacamole_entity instead of
+-- guacamole_user
+--
+
+-- Add new entity_id column
+ALTER TABLE guacamole_user_permission ADD COLUMN entity_id int(11);
+
+-- Update guacamole_user_permission to point to the guacamole_entity
+-- that has been granted the permission
+UPDATE guacamole_user_permission SET entity_id = (
+    SELECT entity_id FROM guacamole_user
+    WHERE guacamole_user.user_id = guacamole_user_permission.user_id
+);
+
+-- The entity_id column should now be safely non-NULL
+ALTER TABLE guacamole_user_permission MODIFY entity_id int(11) NOT NULL;
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE guacamole_user_permission
+    ADD CONSTRAINT guacamole_user_permission_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id)
+    ON DELETE CASCADE;
+
+-- Remove user_id column
+ALTER TABLE guacamole_user_permission DROP FOREIGN KEY guacamole_user_permission_ibfk_2;
+ALTER TABLE guacamole_user_permission DROP PRIMARY KEY;
+ALTER TABLE guacamole_user_permission DROP COLUMN user_id;
+
+-- Add new primary key which uses entity_id
+ALTER TABLE guacamole_user_permission
+    ADD PRIMARY KEY (entity_id, affected_user_id, permission);
+
+--
+-- Modify guacamole_system_permission to use guacamole_entity instead of
+-- guacamole_user
+--
+
+-- Add new entity_id column
+ALTER TABLE guacamole_system_permission ADD COLUMN entity_id int(11);
+
+-- Update guacamole_system_permission to point to the guacamole_entity
+-- that has been granted the permission
+UPDATE guacamole_system_permission SET entity_id = (
+    SELECT entity_id FROM guacamole_user
+    WHERE guacamole_user.user_id = guacamole_system_permission.user_id
+);
+
+-- The entity_id column should now be safely non-NULL
+ALTER TABLE guacamole_system_permission MODIFY entity_id int(11) NOT NULL;
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE guacamole_system_permission
+    ADD CONSTRAINT guacamole_system_permission_entity
+    FOREIGN KEY (entity_id)
+    REFERENCES guacamole_entity (entity_id)
+    ON DELETE CASCADE;
+
+-- Remove user_id column
+ALTER TABLE guacamole_system_permission DROP FOREIGN KEY guacamole_system_permission_ibfk_1;
+ALTER TABLE guacamole_system_permission DROP PRIMARY KEY;
+ALTER TABLE guacamole_system_permission DROP COLUMN user_id;
+
+-- Add new primary key which uses entity_id
+ALTER TABLE guacamole_system_permission
+    ADD PRIMARY KEY (entity_id, permission);
+
+--
 -- Table of arbitrary user attributes. Each attribute is simply a name/value
 -- pair associated with a user. Arbitrary attributes are defined by other
 -- extensions. Attributes defined by this extension will be mapped to
@@ -40,6 +353,28 @@ CREATE TABLE guacamole_user_attribute (
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
 --
+-- Table of arbitrary user group attributes. Each attribute is simply a
+-- name/value pair associated with a user group. Arbitrary attributes are
+-- defined by other extensions. Attributes defined by this extension will be
+-- mapped to properly-typed columns of a specific table.
+--
+
+CREATE TABLE guacamole_user_group_attribute (
+
+  `user_group_id`   int(11)       NOT NULL,
+  `attribute_name`  varchar(128)  NOT NULL,
+  `attribute_value` varchar(4096) NOT NULL,
+
+  PRIMARY KEY (`user_group_id`, `attribute_name`),
+  KEY `user_group_id` (`user_group_id`),
+
+  CONSTRAINT `guacamole_user_group_attribute_ibfk_1`
+    FOREIGN KEY (`user_group_id`)
+    REFERENCES `guacamole_user_group` (`user_group_id`) ON DELETE CASCADE
+
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
 -- Table of arbitrary connection attributes. Each attribute is simply a
 -- name/value pair associated with a connection. Arbitrary attributes are
 -- defined by other extensions. Attributes defined by this extension will be

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/1d0fcc17/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql
index ee10dda..54be792 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql
@@ -34,6 +34,22 @@ EXEC sp_bindrule
 GO
 
 --
+-- Entity types
+--
+
+CREATE RULE [guacamole_entity_type_list] AS @list IN (
+    'USER',
+    'USER_GROUP'
+);
+GO
+
+CREATE TYPE [guacamole_entity_type] FROM [nvarchar](16);
+EXEC sp_bindrule
+    'guacamole_entity_type_list',
+    'guacamole_entity_type';
+GO
+
+--
 -- Object permission types
 --
 
@@ -60,6 +76,7 @@ CREATE RULE [guacamole_system_permission_list] AS @list IN (
     'CREATE_CONNECTION_GROUP',
     'CREATE_SHARING_PROFILE',
     'CREATE_USER',
+    'CREATE_USER_GROUP',
     'ADMINISTER'
 );
 GO
@@ -164,6 +181,28 @@ CREATE NONCLUSTERED INDEX [IX_guacamole_connection_parent_id]
 GO
 
 --
+-- Table of base entities which may each be either a user or user group. Other
+-- tables which represent qualities shared by both users and groups will point
+-- to guacamole_entity, while tables which represent qualities specific to
+-- users or groups will point to guacamole_user or guacamole_user_group.
+--
+
+CREATE TABLE [guacamole_entity] (
+
+    [entity_id]     [int] IDENTITY(1,1)     NOT NULL,
+    [name]          [nvarchar](128)         NOT NULL,
+    [type]          [guacamole_entity_type] NOT NULL,
+
+    CONSTRAINT [PK_guacamole_entity]
+        PRIMARY KEY CLUSTERED ([entity_id]),
+
+    CONSTRAINT [AK_guacamole_entity_name_scope]
+        UNIQUE ([type], [name])
+
+);
+GO
+
+--
 -- Table of users. Each user has a unique username and a hashed password
 -- with corresponding salt. Although the authentication system will always set
 -- salted passwords, other systems may set unsalted passwords by simply not
@@ -172,10 +211,10 @@ GO
 
 CREATE TABLE [guacamole_user] (
 
-    [user_id] [int] IDENTITY(1,1) NOT NULL,
+    [user_id]   [int] IDENTITY(1,1) NOT NULL,
+    [entity_id] [int]               NOT NULL,
 
-    -- Username and optionally-salted password
-    [username]      [nvarchar](128) NOT NULL,
+    -- Optionally-salted password
     [password_hash] [binary](32)    NOT NULL,
     [password_salt] [binary](32),
     [password_date] [datetime]      NOT NULL,
@@ -204,8 +243,68 @@ CREATE TABLE [guacamole_user] (
     CONSTRAINT [PK_guacamole_user]
         PRIMARY KEY CLUSTERED ([user_id]),
 
-    CONSTRAINT [AK_guacamole_user_username]
-        UNIQUE ([username])
+    CONSTRAINT [AK_guacamole_user_single_entity]
+        UNIQUE ([entity_id]),
+
+    CONSTRAINT [FK_guacamole_user_entity]
+        FOREIGN KEY ([entity_id])
+        REFERENCES [guacamole_entity] ([entity_id])
+        ON DELETE CASCADE
+
+);
+GO
+
+--
+-- Table of user groups. Each user group may have an arbitrary set of member
+-- users and member groups, with those members inheriting the permissions
+-- granted to that group.
+--
+
+CREATE TABLE [guacamole_user_group] (
+
+    [user_group_id] [int] IDENTITY(1,1) NOT NULL,
+    [entity_id]     [int]               NOT NULL,
+
+    -- Group disabled status
+    [disabled] [bit] NOT NULL DEFAULT 0,
+
+    CONSTRAINT [PK_guacamole_user_group]
+        PRIMARY KEY CLUSTERED ([user_group_id]),
+
+    CONSTRAINT [guacamole_user_group_single_entity]
+        UNIQUE ([entity_id]),
+
+    CONSTRAINT [guacamole_user_group_entity]
+        FOREIGN KEY ([entity_id])
+        REFERENCES [guacamole_entity] ([entity_id])
+        ON DELETE CASCADE
+
+);
+GO
+
+--
+-- Table of users which are members of given user groups.
+--
+
+CREATE TABLE [guacamole_user_group_member] (
+
+    [user_group_id]    [int] NOT NULL,
+    [member_entity_id] [int] NOT NULL,
+
+    CONSTRAINT [PK_guacamole_user_group_member]
+        PRIMARY KEY CLUSTERED ([user_group_id], [member_entity_id]),
+
+    -- Parent must be a user group
+    CONSTRAINT [guacamole_user_group_member_parent_id]
+        FOREIGN KEY ([user_group_id])
+        REFERENCES [guacamole_user_group] ([user_group_id])
+        ON DELETE CASCADE,
+
+    -- Member may be either a user or a user group (any entity)
+    CONSTRAINT [guacamole_user_group_member_entity_id]
+        FOREIGN KEY ([member_entity_id])
+        REFERENCES [guacamole_entity] ([entity_id])
+        -- ON DELETE CASCADE handled by guacamole_delete_entity trigger
 
 );
 GO
@@ -270,6 +369,34 @@ CREATE NONCLUSTERED INDEX [IX_guacamole_user_attribute_user_id]
 GO
 
 --
+-- Table of arbitrary user group attributes. Each attribute is simply a
+-- name/value pair associated with a user group. Arbitrary attributes are
+-- defined by other extensions. Attributes defined by this extension will be
+-- mapped to properly-typed columns of a specific table.
+--
+
+CREATE TABLE [guacamole_user_group_attribute] (
+
+    [user_group_id]   [int]            NOT NULL,
+    [attribute_name]  [nvarchar](128)  NOT NULL,
+    [attribute_value] [nvarchar](4000) NOT NULL,
+
+    CONSTRAINT [PK_guacamole_user_group_attribute]
+        PRIMARY KEY CLUSTERED ([user_group_id], [attribute_name]),
+
+    CONSTRAINT [FK_guacamole_user_attribute_user_group_id]
+        FOREIGN KEY ([user_group_id])
+        REFERENCES [guacamole_user_group] ([user_group_id])
+        ON DELETE CASCADE
+
+);
+
+CREATE NONCLUSTERED INDEX [IX_guacamole_user_group_attribute_user_id]
+    ON [guacamole_user_group_attribute] ([user_group_id])
+    INCLUDE ([attribute_name], [attribute_value]);
+GO
+
+--
 -- Table of arbitrary connection attributes. Each attribute is simply a
 -- name/value pair associated with a connection. Arbitrary attributes are
 -- defined by other extensions. Attributes defined by this extension will be
@@ -403,27 +530,27 @@ CREATE NONCLUSTERED INDEX [IX_guacamole_sharing_profile_parameter_sharing_profil
 GO
 
 --
--- Table of connection permissions. Each connection permission grants a user
--- specific access to a connection.
+-- Table of connection permissions. Each connection permission grants a user or
+-- user group specific access to a connection.
 --
 
 CREATE TABLE [guacamole_connection_permission] (
 
-    [user_id]       [int]                         NOT NULL,
+    [entity_id]     [int]                         NOT NULL,
     [connection_id] [int]                         NOT NULL,
     [permission]    [guacamole_object_permission] NOT NULL,
 
     CONSTRAINT [PK_guacamole_connection_permission]
-        PRIMARY KEY CLUSTERED  ([user_id], [connection_id], [permission]),
+        PRIMARY KEY CLUSTERED  ([entity_id], [connection_id], [permission]),
 
     CONSTRAINT [FK_guacamole_connection_permission_connection_id]
         FOREIGN KEY ([connection_id])
         REFERENCES [guacamole_connection] ([connection_id])
         ON DELETE CASCADE,
 
-    CONSTRAINT [FK_guacamole_connection_permission_user_id]
-        FOREIGN KEY ([user_id])
-        REFERENCES [guacamole_user] ([user_id])
+    CONSTRAINT [FK_guacamole_connection_permission_entity_id]
+        FOREIGN KEY ([entity_id])
+        REFERENCES [guacamole_entity] ([entity_id])
         ON DELETE CASCADE
 
 );
@@ -431,32 +558,32 @@ CREATE TABLE [guacamole_connection_permission] (
 CREATE NONCLUSTERED INDEX [IX_guacamole_connection_permission_connection_id]
     ON [guacamole_connection_permission] ([connection_id]);
 
-CREATE NONCLUSTERED INDEX [IX_guacamole_connection_permission_user_id]
-    ON [guacamole_connection_permission] ([user_id]);
+CREATE NONCLUSTERED INDEX [IX_guacamole_connection_permission_entity_id]
+    ON [guacamole_connection_permission] ([entity_id]);
 GO
 
 --
 -- Table of connection group permissions. Each group permission grants a user
--- specific access to a connection group.
+-- or user group specific access to a connection group.
 --
 
 CREATE TABLE [guacamole_connection_group_permission] (
 
-    [user_id]             [int]                         NOT NULL,
+    [entity_id]           [int]                         NOT NULL,
     [connection_group_id] [int]                         NOT NULL,
     [permission]          [guacamole_object_permission] NOT NULL,
 
     CONSTRAINT [PK_guacamole_connection_group_permission]
-        PRIMARY KEY CLUSTERED ([user_id], [connection_group_id], [permission]),
+        PRIMARY KEY CLUSTERED ([entity_id], [connection_group_id], [permission]),
 
     CONSTRAINT [FK_guacamole_connection_group_permission_connection_group_id]
         FOREIGN KEY ([connection_group_id])
         REFERENCES [guacamole_connection_group] ([connection_group_id])
         ON DELETE CASCADE,
 
-    CONSTRAINT [FK_guacamole_connection_group_permission_user_id]
-        FOREIGN KEY ([user_id])
-        REFERENCES [guacamole_user] ([user_id])
+    CONSTRAINT [FK_guacamole_connection_group_permission_entity_id]
+        FOREIGN KEY ([entity_id])
+        REFERENCES [guacamole_entity] ([entity_id])
         ON DELETE CASCADE
 
 );
@@ -464,32 +591,32 @@ CREATE TABLE [guacamole_connection_group_permission] (
 CREATE NONCLUSTERED INDEX [IX_guacamole_connection_group_permission_connection_group_id]
     ON [guacamole_connection_group_permission] ([connection_group_id]);
 
-CREATE NONCLUSTERED INDEX [IX_guacamole_connection_group_permission_user_id]
-    ON [guacamole_connection_group_permission] ([user_id]);
+CREATE NONCLUSTERED INDEX [IX_guacamole_connection_group_permission_entity_id]
+    ON [guacamole_connection_group_permission] ([entity_id]);
 GO
 
 --
 -- Table of sharing profile permissions. Each sharing profile permission grants
--- a user specific access to a sharing profile.
+-- a user or user group specific access to a sharing profile.
 --
 
 CREATE TABLE [guacamole_sharing_profile_permission] (
 
-    [user_id]            [int]                         NOT NULL,
+    [entity_id]          [int]                         NOT NULL,
     [sharing_profile_id] [int]                         NOT NULL,
     [permission]         [guacamole_object_permission] NOT NULL,
 
     CONSTRAINT [PK_guacamole_sharing_profile_permission]
-        PRIMARY KEY CLUSTERED ([user_id], [sharing_profile_id], [permission]),
+        PRIMARY KEY CLUSTERED ([entity_id], [sharing_profile_id], [permission]),
 
     CONSTRAINT [FK_guacamole_sharing_profile_permission_sharing_profile_id]
         FOREIGN KEY ([sharing_profile_id])
         REFERENCES [guacamole_sharing_profile] ([sharing_profile_id])
         ON DELETE CASCADE,
 
-    CONSTRAINT [FK_guacamole_sharing_profile_permission_user_id]
-        FOREIGN KEY ([user_id])
-        REFERENCES [guacamole_user] ([user_id])
+    CONSTRAINT [FK_guacamole_sharing_profile_permission_entity_id]
+        FOREIGN KEY ([entity_id])
+        REFERENCES [guacamole_entity] ([entity_id])
         ON DELETE CASCADE
 
 );
@@ -497,68 +624,103 @@ CREATE TABLE [guacamole_sharing_profile_permission] (
 CREATE NONCLUSTERED INDEX [IX_guacamole_sharing_profile_permission_sharing_profile_id]
     ON [guacamole_sharing_profile_permission] ([sharing_profile_id]);
 
-CREATE NONCLUSTERED INDEX [IX_guacamole_sharing_profile_permission_user_id]
-    ON [guacamole_sharing_profile_permission] ([user_id]);
+CREATE NONCLUSTERED INDEX [IX_guacamole_sharing_profile_permission_entity_id]
+    ON [guacamole_sharing_profile_permission] ([entity_id]);
 GO
 
 --
--- Table of system permissions. Each system permission grants a user a
--- system-level privilege of some kind.
+-- Table of system permissions. Each system permission grants a user or user
+-- group a system-level privilege of some kind.
 --
 
 CREATE TABLE [guacamole_system_permission] (
 
-    [user_id]    [int]                         NOT NULL,
+    [entity_id]  [int]                         NOT NULL,
     [permission] [guacamole_system_permission] NOT NULL,
 
     CONSTRAINT [PK_guacamole_system_permission]
-        PRIMARY KEY CLUSTERED ([user_id], [permission]),
+        PRIMARY KEY CLUSTERED ([entity_id], [permission]),
 
-    CONSTRAINT [FK_guacamole_system_permission_user_id]
-        FOREIGN KEY ([user_id])
-        REFERENCES [guacamole_user] ([user_id])
+    CONSTRAINT [FK_guacamole_system_permission_entity_id]
+        FOREIGN KEY ([entity_id])
+        REFERENCES [guacamole_entity] ([entity_id])
         ON DELETE CASCADE
 
 );
 
-CREATE NONCLUSTERED INDEX [IX_guacamole_system_permission_user_id]
-    ON [guacamole_system_permission] ([user_id]);
+CREATE NONCLUSTERED INDEX [IX_guacamole_system_permission_entity_id]
+    ON [guacamole_system_permission] ([entity_id]);
 GO
 
 --
--- Table of user permissions. Each user permission grants a user access to
--- another user (the "affected" user) for a specific type of operation.
+-- Table of user permissions. Each user permission grants a user or user group
+-- access to another user (the "affected" user) for a specific type of
+-- operation.
 --
 
 CREATE TABLE [guacamole_user_permission] (
 
-    [user_id]          [int]                         NOT NULL,
+    [entity_id]        [int]                         NOT NULL,
     [affected_user_id] [int]                         NOT NULL,
     [permission]       [guacamole_object_permission] NOT NULL,
 
     CONSTRAINT [PK_guacamole_user_permission]
-        PRIMARY KEY CLUSTERED ([user_id], [affected_user_id], [permission]),
+        PRIMARY KEY CLUSTERED ([entity_id], [affected_user_id], [permission]),
 
     CONSTRAINT [FK_guacamole_user_permission_affected_user_id]
         FOREIGN KEY ([affected_user_id])
-        REFERENCES [guacamole_user] ([user_id]),
-        -- ON DELETE CASCADE handled by guacamole_delete_user trigger
-
-    CONSTRAINT [FK_guacamole_user_permission_user_id]
-        FOREIGN KEY ([user_id])
         REFERENCES [guacamole_user] ([user_id])
-        -- ON DELETE CASCADE handled by guacamole_delete_user trigger
+        ON DELETE CASCADE,
+
+    CONSTRAINT [FK_guacamole_user_permission_entity_id]
+        FOREIGN KEY ([entity_id])
+        REFERENCES [guacamole_entity] ([entity_id])
+        -- ON DELETE CASCADE handled by guacamole_delete_entity trigger
 
 );
 
-CREATE NONCLUSTERED INDEX [IX_guacamole_user_permission_user_id]
-    ON [guacamole_user_permission] ([user_id]);
+CREATE NONCLUSTERED INDEX [IX_guacamole_user_permission_entity_id]
+    ON [guacamole_user_permission] ([entity_id]);
 
 CREATE NONCLUSTERED INDEX [IX_guacamole_user_permission_affected_user_id]
     ON [guacamole_user_permission] ([affected_user_id]);
 GO
 
 --
+-- Table of user group permissions. Each user group permission grants a user
+-- or user group access to a another user group (the "affected" user group) for
+-- a specific type of operation.
+--
+
+CREATE TABLE [guacamole_user_group_permission] (
+
+    [entity_id]              [int]                         NOT NULL,
+    [affected_user_group_id] [int]                         NOT NULL,
+    [permission]             [guacamole_object_permission] NOT NULL,
+
+    CONSTRAINT [PK_guacamole_user_group_permission]
+        PRIMARY KEY CLUSTERED ([entity_id], [affected_user_group_id], [permission]),
+
+    CONSTRAINT [FK_guacamole_user_group_permission_affected_user_group_id]
+        FOREIGN KEY ([affected_user_group_id])
+        REFERENCES [guacamole_user_group] ([user_group_id])
+        ON DELETE CASCADE,
+
+    CONSTRAINT [FK_guacamole_user_group_permission_entity_id]
+        FOREIGN KEY ([entity_id])
+        REFERENCES [guacamole_entity] ([entity_id])
+        -- ON DELETE CASCADE handled by guacamole_delete_entity trigger
+
+);
+
+CREATE NONCLUSTERED INDEX [IX_guacamole_user_group_permission_entity_id]
+    ON [guacamole_user_group_permission] ([entity_id]);
+
+CREATE NONCLUSTERED INDEX [IX_guacamole_user_group_permission_affected_user_group_id]
+    ON [guacamole_user_group_permission] ([affected_user_group_id]);
+GO
+
+--
 -- Table of connection history records. Each record defines a specific user's
 -- session, including the connection used, the start time, and the end time
 -- (if any).
@@ -682,12 +844,12 @@ GO
 
 --
 -- Handle cascading deletion/updates of records in response to deletion of
--- guacamole_user records, where such deletion is not already covered by
+-- guacamole_entity records, where such deletion is not already covered by
 -- ON DELETE CASCADE or ON DELETE SET NULL.
 --
 
-CREATE TRIGGER [guacamole_delete_user]
-   ON [guacamole_user]
+CREATE TRIGGER [guacamole_delete_entity]
+   ON [guacamole_entity]
    INSTEAD OF DELETE
 AS BEGIN
 
@@ -696,13 +858,18 @@ AS BEGIN
 
     -- Delete all associated permissions not covered by ON DELETE CASCADE
     DELETE FROM [guacamole_user_permission]
-    WHERE
-           [user_id] IN (SELECT [user_id] FROM DELETED)
-        OR [user_id] IN (SELECT [user_id] FROM DELETED);
+    WHERE [entity_id] IN (SELECT [entity_id] FROM DELETED);
+
+    DELETE FROM [guacamole_user_group_permission]
+    WHERE [entity_id] IN (SELECT [entity_id] FROM DELETED);
+
+    -- Delete all associated group memberships not covered by ON DELETE CASCADE
+    DELETE FROM [guacamole_user_group_member]
+    WHERE [member_entity_id] IN (SELECT [entity_id] FROM DELETED);
 
     -- Perform original deletion
-    DELETE FROM [guacamole_user]
-    WHERE [user_id] IN (SELECT [user_id] FROM DELETED);
+    DELETE FROM [guacamole_entity]
+    WHERE [entity_id] IN (SELECT [entity_id] FROM DELETED);
 
 END
 GO
@@ -746,6 +913,20 @@ AS BEGIN
     -- Do not take trigger into account when producing row counts for the DELETE
     SET NOCOUNT ON;
 
+    -- Delete all descendant connections
+    WITH [connection_groups] ([connection_group_id]) AS (
+        SELECT [connection_group_id] FROM DELETED
+    UNION ALL
+        SELECT [guacamole_connection_group].[connection_group_id]
+        FROM [guacamole_connection_group]
+        JOIN [connection_groups] ON [connection_groups].[connection_group_id] = [guacamole_connection_group].[parent_id]
+    )
+    DELETE FROM [guacamole_connection]
+    WHERE [parent_id] IN (
+        SELECT [connection_group_id]
+        FROM [connection_groups]
+    );
+
     -- Delete all requested connection groups, including descendants
     WITH [connection_groups] ([connection_group_id]) AS (
         SELECT [connection_group_id] FROM DELETED
@@ -760,10 +941,6 @@ AS BEGIN
         FROM [connection_groups]
     );
 
-    -- Delete all child connections
-    DELETE FROM [guacamole_connection]
-    WHERE [parent_id] IN (SELECT [connection_group_id] FROM DELETED);
-
 END
 GO
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/1d0fcc17/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/002-create-admin-user.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/002-create-admin-user.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/002-create-admin-user.sql
index 5b14651..dcb4257 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/002-create-admin-user.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/002-create-admin-user.sql
@@ -18,43 +18,46 @@
 --
 
 -- Create default user "guacadmin" with password "guacadmin"
+INSERT INTO [guacamole_entity] ([name], [type]) VALUES ('guacadmin', 'USER');
 INSERT INTO [guacamole_user] (
-    [username],
+    [entity_id],
     [password_hash],
     [password_salt],
     [password_date]
 )
-VALUES (
-    'guacadmin',
+SELECT
+    [entity_id],
     0xCA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960,
     0xFE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264,
     getdate()
-);
+FROM [guacamole_entity] WHERE [name] = 'guacadmin';
 
 -- Grant this user all system permissions
 INSERT INTO [guacamole_system_permission]
 SELECT
-    [user_id],
+    [entity_id],
     [permission]
 FROM (
           SELECT 'guacadmin', 'CREATE_CONNECTION'
     UNION SELECT 'guacadmin', 'CREATE_CONNECTION_GROUP'
     UNION SELECT 'guacadmin', 'CREATE_SHARING_PROFILE'
     UNION SELECT 'guacadmin', 'CREATE_USER'
+    UNION SELECT 'guacadmin', 'CREATE_USER_GROUP'
     UNION SELECT 'guacadmin', 'ADMINISTER'
 ) [permissions] ([username], [permission])
-JOIN [guacamole_user] ON [permissions].[username] = [guacamole_user].[username];
+JOIN [guacamole_entity] ON [permissions].[username] = [guacamole_entity].[name] AND [guacamole_entity].[type] = 'USER';
 
 INSERT INTO [guacamole_user_permission]
 SELECT
+    [guacamole_entity].[entity_id],
     [guacamole_user].[user_id],
-    [affected].[user_id],
     [permission]
 FROM (
           SELECT 'guacadmin', 'guacadmin', 'READ'
     UNION SELECT 'guacadmin', 'guacadmin', 'UPDATE'
     UNION SELECT 'guacadmin', 'guacadmin', 'ADMINISTER'
 ) [permissions] ([username], [affected_username], [permission])
-JOIN [guacamole_user]          ON permissions.username = [guacamole_user].[username]
-JOIN [guacamole_user] [affected] ON permissions.affected_username = affected.username;
+JOIN [guacamole_entity]            ON [permissions].[username] = [guacamole_entity].[name] AND [guacamole_entity].[type] = 'USER'
+JOIN [guacamole_entity] [affected] ON [permissions].[affected_username] = [affected].[name] AND [guacamole_entity].[type] = 'USER'
+JOIN [guacamole_user]              ON [guacamole_user].[entity_id] = [affected].[entity_id];
 GO

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/1d0fcc17/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.0.0.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.0.0.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.0.0.sql
index cb02dd5..6e9133a 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.0.0.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.0.0.sql
@@ -18,6 +18,510 @@
 --
 
 --
+-- Add new system-level permission
+--
+
+EXEC sp_unbindrule 'guacamole_system_permission';
+DROP RULE [guacamole_system_permission_list];
+GO
+
+CREATE RULE [guacamole_system_permission_list] AS @list IN (
+    'CREATE_CONNECTION',
+    'CREATE_CONNECTION_GROUP',
+    'CREATE_SHARING_PROFILE',
+    'CREATE_USER',
+    'CREATE_USER_GROUP',
+    'ADMINISTER'
+);
+GO
+
+EXEC sp_bindrule
+    'guacamole_system_permission_list',
+    'guacamole_system_permission';
+GO
+
+--
+-- Entity types
+--
+
+CREATE RULE [guacamole_entity_type_list] AS @list IN (
+    'USER',
+    'USER_GROUP'
+);
+GO
+
+CREATE TYPE [guacamole_entity_type] FROM [nvarchar](16);
+EXEC sp_bindrule
+    'guacamole_entity_type_list',
+    'guacamole_entity_type';
+GO
+
+--
+-- Table of base entities which may each be either a user or user group. Other
+-- tables which represent qualities shared by both users and groups will point
+-- to guacamole_entity, while tables which represent qualities specific to
+-- users or groups will point to guacamole_user or guacamole_user_group.
+--
+
+CREATE TABLE [guacamole_entity] (
+
+    [entity_id]     [int] IDENTITY(1,1)     NOT NULL,
+    [name]          [nvarchar](128)         NOT NULL,
+    [type]          [guacamole_entity_type] NOT NULL,
+
+    CONSTRAINT [PK_guacamole_entity]
+        PRIMARY KEY CLUSTERED ([entity_id]),
+
+    CONSTRAINT [AK_guacamole_entity_name_scope]
+        UNIQUE ([type], [name])
+
+);
+GO
+
+--
+-- Table of user groups. Each user group may have an arbitrary set of member
+-- users and member groups, with those members inheriting the permissions
+-- granted to that group.
+--
+
+CREATE TABLE [guacamole_user_group] (
+
+    [user_group_id] [int] IDENTITY(1,1) NOT NULL,
+    [entity_id]     [int]               NOT NULL,
+
+    -- Group disabled status
+    [disabled] [bit] NOT NULL DEFAULT 0,
+
+    CONSTRAINT [PK_guacamole_user_group]
+        PRIMARY KEY CLUSTERED ([user_group_id]),
+
+    CONSTRAINT [guacamole_user_group_single_entity]
+        UNIQUE ([entity_id]),
+
+    CONSTRAINT [guacamole_user_group_entity]
+        FOREIGN KEY ([entity_id])
+        REFERENCES [guacamole_entity] ([entity_id])
+        ON DELETE CASCADE
+
+);
+GO
+
+--
+-- Table of users which are members of given user groups.
+--
+
+CREATE TABLE [guacamole_user_group_member] (
+
+    [user_group_id]    [int] NOT NULL,
+    [member_entity_id] [int] NOT NULL,
+
+    CONSTRAINT [PK_guacamole_user_group_member]
+        PRIMARY KEY CLUSTERED ([user_group_id], [member_entity_id]),
+
+    -- Parent must be a user group
+    CONSTRAINT [guacamole_user_group_member_parent_id]
+        FOREIGN KEY ([user_group_id])
+        REFERENCES [guacamole_user_group] ([user_group_id])
+        ON DELETE CASCADE,
+
+    -- Member may be either a user or a user group (any entity)
+    CONSTRAINT [guacamole_user_group_member_entity_id]
+        FOREIGN KEY ([member_entity_id])
+        REFERENCES [guacamole_entity] ([entity_id])
+        -- ON DELETE CASCADE handled by guacamole_delete_entity trigger
+
+);
+GO
+
+--
+-- Table of user group permissions. Each user group permission grants a user
+-- or user group access to a another user group (the "affected" user group) for
+-- a specific type of operation.
+--
+
+CREATE TABLE [guacamole_user_group_permission] (
+
+    [entity_id]              [int]                         NOT NULL,
+    [affected_user_group_id] [int]                         NOT NULL,
+    [permission]             [guacamole_object_permission] NOT NULL,
+
+    CONSTRAINT [PK_guacamole_user_group_permission]
+        PRIMARY KEY CLUSTERED ([entity_id], [affected_user_group_id], [permission]),
+
+    CONSTRAINT [FK_guacamole_user_group_permission_affected_user_group_id]
+        FOREIGN KEY ([affected_user_group_id])
+        REFERENCES [guacamole_user_group] ([user_group_id])
+        ON DELETE CASCADE,
+
+    CONSTRAINT [FK_guacamole_user_group_permission_entity_id]
+        FOREIGN KEY ([entity_id])
+        REFERENCES [guacamole_entity] ([entity_id])
+        -- ON DELETE CASCADE handled by guacamole_delete_entity trigger
+
+);
+
+CREATE NONCLUSTERED INDEX [IX_guacamole_user_group_permission_entity_id]
+    ON [guacamole_user_group_permission] ([entity_id]);
+
+CREATE NONCLUSTERED INDEX [IX_guacamole_user_group_permission_affected_user_group_id]
+    ON [guacamole_user_group_permission] ([affected_user_group_id]);
+GO
+
+--
+-- The guacamole_delete_entity trigger effectively replaces the
+-- guacamole_delete_user trigger, which is no longer necessary and will cease
+-- being correct after the columns of existing tables are updated.
+--
+
+DROP TRIGGER [guacamole_delete_user];
+GO
+
+--
+-- Modify guacamole_user table to use guacamole_entity as a base
+--
+
+-- Add new entity_id column
+ALTER TABLE [guacamole_user] ADD [entity_id] [int];
+GO
+
+-- Create user entities for each guacamole_user entry
+INSERT INTO [guacamole_entity] ([name], [type])
+SELECT [username], 'USER' FROM [guacamole_user];
+GO
+
+-- Update guacamole_user to point to corresponding guacamole_entity
+UPDATE [guacamole_user] SET [entity_id] = (
+    SELECT [entity_id] FROM [guacamole_entity]
+    WHERE
+            [username] = [guacamole_entity].[name]
+        AND type = 'USER'
+);
+GO
+
+-- The entity_id column should now be safely non-NULL
+ALTER TABLE [guacamole_user]
+    ALTER COLUMN [entity_id] [int] NOT NULL;
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE [guacamole_user]
+    ADD CONSTRAINT [AK_guacamole_user_single_entity]
+    UNIQUE ([entity_id]);
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE [guacamole_user]
+    ADD CONSTRAINT [FK_guacamole_user_entity]
+    FOREIGN KEY ([entity_id])
+    REFERENCES [guacamole_entity] ([entity_id])
+    ON DELETE CASCADE;
+
+-- The username column can now safely be removed
+ALTER TABLE [guacamole_user] DROP [AK_guacamole_user_username];
+ALTER TABLE [guacamole_user] DROP COLUMN [username];
+GO
+
+--
+-- Modify guacamole_connection_permission to use guacamole_entity instead of
+-- guacamole_user
+--
+
+-- Add new entity_id column
+ALTER TABLE [guacamole_connection_permission] ADD [entity_id] [int];
+GO
+
+-- Update guacamole_connection_permission to point to the guacamole_entity
+-- that has been granted the permission
+UPDATE [guacamole_connection_permission] SET [entity_id] = (
+    SELECT [entity_id] FROM [guacamole_user]
+    WHERE [guacamole_user].[user_id] = [guacamole_connection_permission].[user_id]
+);
+GO
+
+-- The entity_id column should now be safely non-NULL
+ALTER TABLE [guacamole_connection_permission]
+    ALTER COLUMN [entity_id] [int] NOT NULL;
+
+-- Remove user_id column
+DROP INDEX [IX_guacamole_connection_permission_user_id] ON [guacamole_connection_permission];
+ALTER TABLE [guacamole_connection_permission] DROP [PK_guacamole_connection_permission];
+ALTER TABLE [guacamole_connection_permission] DROP [FK_guacamole_connection_permission_user_id];
+ALTER TABLE [guacamole_connection_permission] DROP COLUMN [user_id];
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE [guacamole_connection_permission]
+    ADD CONSTRAINT [FK_guacamole_connection_permission_entity_id]
+    FOREIGN KEY ([entity_id])
+    REFERENCES [guacamole_entity] ([entity_id])
+    ON DELETE CASCADE;
+
+CREATE NONCLUSTERED INDEX [IX_guacamole_connection_permission_entity_id]
+    ON [guacamole_connection_permission] ([entity_id]);
+
+-- Add new primary key which uses entity_id
+ALTER TABLE [guacamole_connection_permission]
+    ADD CONSTRAINT [PK_guacamole_connection_permission]
+    PRIMARY KEY CLUSTERED ([entity_id], [connection_id], [permission]);
+GO
+
+--
+-- Modify guacamole_connection_group_permission to use guacamole_entity instead
+-- of guacamole_user
+--
+
+-- Add new entity_id column
+ALTER TABLE [guacamole_connection_group_permission] ADD [entity_id] [int];
+GO
+
+-- Update guacamole_connection_group_permission to point to the guacamole_entity
+-- that has been granted the permission
+UPDATE guacamole_connection_group_permission SET entity_id = (
+    SELECT entity_id FROM guacamole_user
+    WHERE guacamole_user.user_id = guacamole_connection_group_permission.user_id
+);
+GO
+
+-- The entity_id column should now be safely non-NULL
+ALTER TABLE [guacamole_connection_group_permission]
+    ALTER COLUMN [entity_id] [int] NOT NULL;
+
+-- Remove user_id column
+DROP INDEX [IX_guacamole_connection_group_permission_user_id] ON [guacamole_connection_group_permission];
+ALTER TABLE [guacamole_connection_group_permission] DROP [PK_guacamole_connection_group_permission];
+ALTER TABLE [guacamole_connection_group_permission] DROP [FK_guacamole_connection_group_permission_user_id];
+ALTER TABLE [guacamole_connection_group_permission] DROP COLUMN user_id;
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE [guacamole_connection_group_permission]
+    ADD CONSTRAINT [FK_guacamole_connection_group_permission_entity_id]
+    FOREIGN KEY ([entity_id])
+    REFERENCES [guacamole_entity] ([entity_id])
+    ON DELETE CASCADE;
+
+CREATE NONCLUSTERED INDEX [IX_guacamole_connection_group_permission_entity_id]
+    ON [guacamole_connection_group_permission] ([entity_id]);
+
+-- Add new primary key which uses entity_id
+ALTER TABLE [guacamole_connection_group_permission]
+    ADD CONSTRAINT [PK_guacamole_connection_group_permission]
+    PRIMARY KEY CLUSTERED ([entity_id], [connection_group_id], [permission]);
+GO
+
+--
+-- Modify guacamole_sharing_profile_permission to use guacamole_entity instead
+-- of guacamole_user
+--
+
+-- Add new entity_id column
+ALTER TABLE [guacamole_sharing_profile_permission] ADD [entity_id] [int];
+GO
+
+-- Update guacamole_sharing_profile_permission to point to the guacamole_entity
+-- that has been granted the permission
+UPDATE guacamole_sharing_profile_permission SET entity_id = (
+    SELECT entity_id FROM guacamole_user
+    WHERE guacamole_user.user_id = guacamole_sharing_profile_permission.user_id
+);
+GO
+
+-- The entity_id column should now be safely non-NULL
+ALTER TABLE [guacamole_sharing_profile_permission]
+    ALTER COLUMN [entity_id] [int] NOT NULL;
+
+-- Remove user_id column
+DROP INDEX [IX_guacamole_sharing_profile_permission_user_id] ON [guacamole_sharing_profile_permission];
+ALTER TABLE [guacamole_sharing_profile_permission] DROP [PK_guacamole_sharing_profile_permission];
+ALTER TABLE [guacamole_sharing_profile_permission] DROP [FK_guacamole_sharing_profile_permission_user_id];
+ALTER TABLE [guacamole_sharing_profile_permission] DROP COLUMN user_id;
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE [guacamole_sharing_profile_permission]
+    ADD CONSTRAINT [FK_guacamole_sharing_profile_permission_entity_id]
+    FOREIGN KEY ([entity_id])
+    REFERENCES [guacamole_entity] ([entity_id])
+    ON DELETE CASCADE;
+
+CREATE NONCLUSTERED INDEX [IX_guacamole_sharing_profile_permission_entity_id]
+    ON [guacamole_sharing_profile_permission] ([entity_id]);
+
+-- Add new primary key which uses entity_id
+ALTER TABLE [guacamole_sharing_profile_permission]
+    ADD CONSTRAINT [PK_guacamole_sharing_profile_permission]
+    PRIMARY KEY CLUSTERED ([entity_id], [sharing_profile_id], [permission]);
+GO
+
+--
+-- Modify guacamole_user_permission to use guacamole_entity instead of
+-- guacamole_user
+--
+
+-- Add new entity_id column
+ALTER TABLE [guacamole_user_permission] ADD [entity_id] [int];
+GO
+
+-- Update guacamole_user_permission to point to the guacamole_entity
+-- that has been granted the permission
+UPDATE guacamole_user_permission SET entity_id = (
+    SELECT entity_id FROM guacamole_user
+    WHERE guacamole_user.user_id = guacamole_user_permission.user_id
+);
+GO
+
+-- The entity_id column should now be safely non-NULL
+ALTER TABLE [guacamole_user_permission]
+    ALTER COLUMN [entity_id] [int] NOT NULL;
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE [guacamole_user_permission]
+    ADD CONSTRAINT [FK_guacamole_user_permission_entity_id]
+    FOREIGN KEY ([entity_id])
+    REFERENCES [guacamole_entity] ([entity_id]);
+    -- ON DELETE CASCADE handled by guacamole_delete_entity trigger
+
+-- The affected_user_id column now has ON DELETE CASCADE
+ALTER TABLE [guacamole_user_permission] DROP [FK_guacamole_user_permission_affected_user_id];
+ALTER TABLE [guacamole_user_permission]
+    ADD CONSTRAINT [FK_guacamole_user_permission_affected_user_id]
+        FOREIGN KEY ([affected_user_id])
+        REFERENCES [guacamole_user] ([user_id])
+        ON DELETE CASCADE;
+
+CREATE NONCLUSTERED INDEX [IX_guacamole_user_permission_entity_id]
+    ON [guacamole_user_permission] ([entity_id]);
+
+-- Remove user_id column
+DROP INDEX [IX_guacamole_user_permission_user_id] ON [guacamole_user_permission];
+ALTER TABLE [guacamole_user_permission] DROP [PK_guacamole_user_permission];
+ALTER TABLE [guacamole_user_permission] DROP [FK_guacamole_user_permission_user_id];
+ALTER TABLE [guacamole_user_permission] DROP COLUMN user_id;
+
+-- Add new primary key which uses entity_id
+ALTER TABLE [guacamole_user_permission]
+    ADD CONSTRAINT [PK_guacamole_user_permission]
+    PRIMARY KEY CLUSTERED ([entity_id], [affected_user_id], [permission]);
+GO
+
+--
+-- Modify guacamole_system_permission to use guacamole_entity instead of
+-- guacamole_user
+--
+
+-- Add new entity_id column
+ALTER TABLE [guacamole_system_permission] ADD [entity_id] [int];
+GO
+
+-- Update guacamole_system_permission to point to the guacamole_entity
+-- that has been granted the permission
+UPDATE [guacamole_system_permission] SET [entity_id] = (
+    SELECT [entity_id] FROM [guacamole_user]
+    WHERE [guacamole_user].[user_id] = [guacamole_system_permission].[user_id]
+);
+GO
+
+-- The entity_id column should now be safely non-NULL
+ALTER TABLE [guacamole_system_permission]
+    ALTER COLUMN [entity_id] [int] NOT NULL;
+
+-- Remove user_id column
+DROP INDEX [IX_guacamole_system_permission_user_id] ON [guacamole_system_permission];
+ALTER TABLE [guacamole_system_permission] DROP [PK_guacamole_system_permission];
+ALTER TABLE [guacamole_system_permission] DROP [FK_guacamole_system_permission_user_id];
+ALTER TABLE [guacamole_system_permission] DROP COLUMN [user_id];
+
+-- The entity_id column should now safely point to guacamole_entity entries
+ALTER TABLE [guacamole_system_permission]
+    ADD CONSTRAINT [FK_guacamole_system_permission_entity_id]
+    FOREIGN KEY ([entity_id])
+    REFERENCES [guacamole_entity] ([entity_id])
+    ON DELETE CASCADE;
+
+CREATE NONCLUSTERED INDEX [IX_guacamole_system_permission_entity_id]
+    ON [guacamole_system_permission] ([entity_id]);
+
+-- Add new primary key which uses entity_id
+ALTER TABLE [guacamole_system_permission]
+    ADD CONSTRAINT [PK_guacamole_system_permission]
+    PRIMARY KEY CLUSTERED ([entity_id], [permission]);
+GO
+
+--
+-- Handle cascading deletion/updates of records in response to deletion of
+-- guacamole_entity records, where such deletion is not already covered by
+-- ON DELETE CASCADE or ON DELETE SET NULL.
+--
+
+CREATE TRIGGER [guacamole_delete_entity]
+   ON [guacamole_entity]
+   INSTEAD OF DELETE
+AS BEGIN
+
+    -- Do not take trigger into account when producing row counts for the DELETE
+    SET NOCOUNT ON;
+
+    -- Delete all associated permissions not covered by ON DELETE CASCADE
+    DELETE FROM [guacamole_user_permission]
+    WHERE [entity_id] IN (SELECT [entity_id] FROM DELETED);
+
+    DELETE FROM [guacamole_user_group_permission]
+    WHERE [entity_id] IN (SELECT [entity_id] FROM DELETED);
+
+    -- Delete all associated group memberships not covered by ON DELETE CASCADE
+    DELETE FROM [guacamole_user_group_member]
+    WHERE [member_entity_id] IN (SELECT [entity_id] FROM DELETED);
+
+    -- Perform original deletion
+    DELETE FROM [guacamole_entity]
+    WHERE [entity_id] IN (SELECT [entity_id] FROM DELETED);
+
+END
+GO
+
+--
+-- Update guacamole_delete_connection_group trigger to remove descendant
+-- connections first.
+--
+
+DROP TRIGGER [guacamole_delete_connection_group];
+GO
+
+CREATE TRIGGER [guacamole_delete_connection_group]
+   ON [guacamole_connection_group]
+   INSTEAD OF DELETE
+AS BEGIN
+
+    -- Do not take trigger into account when producing row counts for the DELETE
+    SET NOCOUNT ON;
+
+    -- Delete all descendant connections
+    WITH [connection_groups] ([connection_group_id]) AS (
+        SELECT [connection_group_id] FROM DELETED
+    UNION ALL
+        SELECT [guacamole_connection_group].[connection_group_id]
+        FROM [guacamole_connection_group]
+        JOIN [connection_groups] ON [connection_groups].[connection_group_id] = [guacamole_connection_group].[parent_id]
+    )
+    DELETE FROM [guacamole_connection]
+    WHERE [parent_id] IN (
+        SELECT [connection_group_id]
+        FROM [connection_groups]
+    );
+
+    -- Delete all requested connection groups, including descendants
+    WITH [connection_groups] ([connection_group_id]) AS (
+        SELECT [connection_group_id] FROM DELETED
+    UNION ALL
+        SELECT [guacamole_connection_group].[connection_group_id]
+        FROM [guacamole_connection_group]
+        JOIN [connection_groups] ON [connection_groups].[connection_group_id] = [guacamole_connection_group].[parent_id]
+    )
+    DELETE FROM [guacamole_connection_group]
+    WHERE [connection_group_id] IN (
+        SELECT [connection_group_id]
+        FROM [connection_groups]
+    );
+
+END
+GO
+
+--
 -- Table of arbitrary user attributes. Each attribute is simply a name/value
 -- pair associated with a user. Arbitrary attributes are defined by other
 -- extensions. Attributes defined by this extension will be mapped to
@@ -46,6 +550,34 @@ CREATE NONCLUSTERED INDEX [IX_guacamole_user_attribute_user_id]
 GO
 
 --
+-- Table of arbitrary user group attributes. Each attribute is simply a
+-- name/value pair associated with a user group. Arbitrary attributes are
+-- defined by other extensions. Attributes defined by this extension will be
+-- mapped to properly-typed columns of a specific table.
+--
+
+CREATE TABLE [guacamole_user_group_attribute] (
+
+    [user_group_id]   [int]            NOT NULL,
+    [attribute_name]  [nvarchar](128)  NOT NULL,
+    [attribute_value] [nvarchar](4000) NOT NULL,
+
+    CONSTRAINT [PK_guacamole_user_group_attribute]
+        PRIMARY KEY CLUSTERED ([user_group_id], [attribute_name]),
+
+    CONSTRAINT [FK_guacamole_user_attribute_user_group_id]
+        FOREIGN KEY ([user_group_id])
+        REFERENCES [guacamole_user_group] ([user_group_id])
+        ON DELETE CASCADE
+
+);
+
+CREATE NONCLUSTERED INDEX [IX_guacamole_user_group_attribute_user_id]
+    ON [guacamole_user_group_attribute] ([user_group_id])
+    INCLUDE ([attribute_name], [attribute_value]);
+GO
+
+--
 -- Table of arbitrary connection attributes. Each attribute is simply a
 -- name/value pair associated with a connection. Arbitrary attributes are
 -- defined by other extensions. Attributes defined by this extension will be


[08/38] guacamole-client git commit: GUACAMOLE-220: Use effective permissions when deciding whether a user has permission to perform an action.

Posted by vn...@apache.org.
GUACAMOLE-220: Use effective permissions when deciding whether a user has permission to perform an action.


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

Branch: refs/heads/master
Commit: 199f518cdb7e888de1f574d871e5f3847041a327
Parents: 0a69630
Author: Michael Jumper <mj...@apache.org>
Authored: Sun Apr 8 00:16:12 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:51 2018 -0700

----------------------------------------------------------------------
 .../jdbc/base/ModeledChildDirectoryObjectService.java  |  7 ++++---
 .../auth/jdbc/base/ModeledDirectoryObjectService.java  | 13 ++++++++-----
 .../auth/jdbc/connection/ConnectionService.java        | 10 +++++-----
 .../jdbc/connectiongroup/ConnectionGroupService.java   | 10 +++++-----
 .../jdbc/permission/AbstractPermissionService.java     |  4 ++--
 .../permission/ModeledObjectPermissionService.java     |  3 ++-
 .../jdbc/sharingprofile/SharingProfileService.java     | 10 +++++-----
 .../apache/guacamole/auth/jdbc/user/ModeledUser.java   |  5 +++--
 .../apache/guacamole/auth/jdbc/user/UserService.java   |  6 +++---
 9 files changed, 37 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/199f518c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledChildDirectoryObjectService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledChildDirectoryObjectService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledChildDirectoryObjectService.java
index 74ca5bb..f517e27 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledChildDirectoryObjectService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledChildDirectoryObjectService.java
@@ -53,7 +53,8 @@ public abstract class ModeledChildDirectoryObjectService<InternalType extends Mo
     /**
      * Returns the permission set associated with the given user and related
      * to the type of objects which can be parents of the child objects handled
-     * by this directory object service.
+     * by this directory object service, taking into account permission
+     * inheritance via user groups.
      *
      * @param user
      *     The user whose permissions are being retrieved.
@@ -66,7 +67,7 @@ public abstract class ModeledChildDirectoryObjectService<InternalType extends Mo
      * @throws GuacamoleException
      *     If permission to read the user's permissions is denied.
      */
-    protected abstract ObjectPermissionSet getParentPermissionSet(
+    protected abstract ObjectPermissionSet getParentEffectivePermissionSet(
             ModeledAuthenticatedUser user) throws GuacamoleException;
 
     /**
@@ -155,7 +156,7 @@ public abstract class ModeledChildDirectoryObjectService<InternalType extends Mo
         Collection<String> modifiedParents = getModifiedParents(user, identifier, model);
         if (!modifiedParents.isEmpty()) {
 
-            ObjectPermissionSet permissionSet = getParentPermissionSet(user);
+            ObjectPermissionSet permissionSet = getParentEffectivePermissionSet(user);
             Collection<String> updateableParents = permissionSet.getAccessibleObjects(
                 Collections.singleton(ObjectPermission.Type.UPDATE),
                 modifiedParents

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/199f518c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java
index 3e3e707..e87d664 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java
@@ -126,7 +126,8 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
 
     /**
      * Returns whether the given user has permission to create the type of
-     * objects that this directory object service manages.
+     * objects that this directory object service manages, taking into account
+     * permission inheritance through user groups.
      *
      * @param user
      *     The user being checked.
@@ -143,7 +144,8 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
 
     /**
      * Returns whether the given user has permission to perform a certain
-     * action on a specific object managed by this directory object service.
+     * action on a specific object managed by this directory object service,
+     * taking into account permission inheritance through user groups.
      *
      * @param user
      *     The user being checked.
@@ -166,7 +168,7 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
             throws GuacamoleException {
 
         // Get object permissions
-        ObjectPermissionSet permissionSet = getPermissionSet(user);
+        ObjectPermissionSet permissionSet = getEffectivePermissionSet(user);
         
         // Return whether permission is granted
         return user.getUser().isAdministrator()
@@ -176,7 +178,8 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
  
     /**
      * Returns the permission set associated with the given user and related
-     * to the type of objects handled by this directory object service.
+     * to the type of objects handled by this directory object service, taking
+     * into account permission inheritance via user groups.
      *
      * @param user
      *     The user whose permissions are being retrieved.
@@ -189,7 +192,7 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
      * @throws GuacamoleException
      *     If permission to read the user's permissions is denied.
      */
-    protected abstract ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user)
+    protected abstract ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
             throws GuacamoleException;
 
     /**

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/199f518c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java
index 983f395..11e3792 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java
@@ -131,26 +131,26 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
             throws GuacamoleException {
 
         // Return whether user has explicit connection creation permission
-        SystemPermissionSet permissionSet = user.getUser().getSystemPermissions();
+        SystemPermissionSet permissionSet = user.getUser().getEffectivePermissions().getSystemPermissions();
         return permissionSet.hasPermission(SystemPermission.Type.CREATE_CONNECTION);
 
     }
 
     @Override
-    protected ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user)
+    protected ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
             throws GuacamoleException {
 
         // Return permissions related to connections 
-        return user.getUser().getConnectionPermissions();
+        return user.getUser().getEffectivePermissions().getConnectionPermissions();
 
     }
 
     @Override
-    protected ObjectPermissionSet getParentPermissionSet(ModeledAuthenticatedUser user)
+    protected ObjectPermissionSet getParentEffectivePermissionSet(ModeledAuthenticatedUser user)
             throws GuacamoleException {
 
         // Connections are contained by connection groups
-        return user.getUser().getConnectionGroupPermissions();
+        return user.getUser().getEffectivePermissions().getConnectionGroupPermissions();
 
     }
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/199f518c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java
index e23081c..34d039c 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java
@@ -112,26 +112,26 @@ public class ConnectionGroupService extends ModeledChildDirectoryObjectService<M
             throws GuacamoleException {
 
         // Return whether user has explicit connection group creation permission
-        SystemPermissionSet permissionSet = user.getUser().getSystemPermissions();
+        SystemPermissionSet permissionSet = user.getUser().getEffectivePermissions().getSystemPermissions();
         return permissionSet.hasPermission(SystemPermission.Type.CREATE_CONNECTION_GROUP);
 
     }
 
     @Override
-    protected ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user)
+    protected ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
             throws GuacamoleException {
 
         // Return permissions related to connection groups 
-        return user.getUser().getConnectionGroupPermissions();
+        return user.getUser().getEffectivePermissions().getConnectionGroupPermissions();
 
     }
 
     @Override
-    protected ObjectPermissionSet getParentPermissionSet(ModeledAuthenticatedUser user)
+    protected ObjectPermissionSet getParentEffectivePermissionSet(ModeledAuthenticatedUser user)
             throws GuacamoleException {
 
         // Connection groups are contained by other connection groups
-        return user.getUser().getConnectionGroupPermissions();
+        return user.getUser().getEffectivePermissions().getConnectionGroupPermissions();
 
     }
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/199f518c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/AbstractPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/AbstractPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/AbstractPermissionService.java
index 8635488..74f35fb 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/AbstractPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/AbstractPermissionService.java
@@ -45,7 +45,7 @@ public abstract class AbstractPermissionService<PermissionSetType extends Permis
      * Determines whether the given user can read the permissions currently
      * granted to the given target user. If the reading user and the target
      * user are not the same, then explicit READ or SYSTEM_ADMINISTER access is
-     * required.
+     * required. Permission inheritance via user groups is taken into account.
      *
      * @param user
      *     The user attempting to read permissions.
@@ -72,7 +72,7 @@ public abstract class AbstractPermissionService<PermissionSetType extends Permis
             return true;
 
         // Can read permissions on target user if explicit READ is granted
-        ObjectPermissionSet userPermissionSet = user.getUser().getUserPermissions();
+        ObjectPermissionSet userPermissionSet = user.getUser().getEffectivePermissions().getUserPermissions();
         return userPermissionSet.hasPermission(ObjectPermission.Type.READ, targetUser.getIdentifier());
 
     }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/199f518c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
index 30ea5d7..b1229ae 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
@@ -67,6 +67,7 @@ public abstract class ModeledObjectPermissionService
      * depends on whether the current user is a system administrator, whether
      * they have explicit UPDATE permission on the target user, and whether
      * they have explicit ADMINISTER permission on all affected objects.
+     * Permission inheritance via user groups is taken into account.
      *
      * @param user
      *     The user who is changing permissions.
@@ -95,7 +96,7 @@ public abstract class ModeledObjectPermissionService
             return true;
         
         // Verify user has update permission on the target user
-        ObjectPermissionSet userPermissionSet = user.getUser().getUserPermissions();
+        ObjectPermissionSet userPermissionSet = user.getUser().getEffectivePermissions().getUserPermissions();
         if (!userPermissionSet.hasPermission(ObjectPermission.Type.UPDATE, targetUser.getIdentifier()))
             return false;
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/199f518c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileService.java
index 4b4d2d1..4ca492c 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileService.java
@@ -112,26 +112,26 @@ public class SharingProfileService
             throws GuacamoleException {
 
         // Return whether user has explicit sharing profile creation permission
-        SystemPermissionSet permissionSet = user.getUser().getSystemPermissions();
+        SystemPermissionSet permissionSet = user.getUser().getEffectivePermissions().getSystemPermissions();
         return permissionSet.hasPermission(SystemPermission.Type.CREATE_SHARING_PROFILE);
 
     }
 
     @Override
-    protected ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user)
+    protected ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
             throws GuacamoleException {
 
         // Return permissions related to sharing profiles
-        return user.getUser().getSharingProfilePermissions();
+        return user.getUser().getEffectivePermissions().getSharingProfilePermissions();
 
     }
 
     @Override
-    protected ObjectPermissionSet getParentPermissionSet(ModeledAuthenticatedUser user)
+    protected ObjectPermissionSet getParentEffectivePermissionSet(ModeledAuthenticatedUser user)
             throws GuacamoleException {
 
         // Sharing profiles are children of connections
-        return user.getUser().getConnectionPermissions();
+        return user.getUser().getEffectivePermissions().getConnectionPermissions();
 
     }
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/199f518c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
index 39f1636..737aec8 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
@@ -333,7 +333,8 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
 
     /**
      * Returns whether this user is a system administrator, and thus is not
-     * restricted by permissions.
+     * restricted by permissions, taking into account permission inheritance
+     * via user groups.
      *
      * @return
      *    true if this user is a system administrator, false otherwise.
@@ -343,7 +344,7 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
      *    status.
      */
     public boolean isAdministrator() throws GuacamoleException {
-        SystemPermissionSet systemPermissionSet = getSystemPermissions();
+        SystemPermissionSet systemPermissionSet = getEffectivePermissions().getSystemPermissions();
         return systemPermissionSet.hasPermission(SystemPermission.Type.ADMINISTER);
     }
     

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/199f518c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
index 9f7fb87..2c70e22 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
@@ -216,17 +216,17 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
             throws GuacamoleException {
 
         // Return whether user has explicit user creation permission
-        SystemPermissionSet permissionSet = user.getUser().getSystemPermissions();
+        SystemPermissionSet permissionSet = user.getUser().getEffectivePermissions().getSystemPermissions();
         return permissionSet.hasPermission(SystemPermission.Type.CREATE_USER);
 
     }
 
     @Override
-    protected ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user)
+    protected ObjectPermissionSet getEffectivePermissionSet(ModeledAuthenticatedUser user)
             throws GuacamoleException {
 
         // Return permissions related to users
-        return user.getUser().getUserPermissions();
+        return user.getUser().getEffectivePermissions().getUserPermissions();
 
     }
 


[33/38] guacamole-client git commit: GUACAMOLE-220: Rows are deleted to modify the one-to-many relationship, not to establish it.

Posted by vn...@apache.org.
GUACAMOLE-220: Rows are deleted to modify the one-to-many relationship, not to establish it.

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

Branch: refs/heads/master
Commit: 7521cdc0aea8f307e1097a82295fd3e9a2538660
Parents: 5fdd0bb
Author: Michael Jumper <mj...@apache.org>
Authored: Thu Sep 27 20:10:32 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Thu Sep 27 20:10:32 2018 -0700

----------------------------------------------------------------------
 .../org/apache/guacamole/auth/jdbc/base/ObjectRelationMapper.java  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/7521cdc0/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ObjectRelationMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ObjectRelationMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ObjectRelationMapper.java
index 082db0f..c2763ec 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ObjectRelationMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ObjectRelationMapper.java
@@ -56,7 +56,7 @@ public interface ObjectRelationMapper<ParentModelType extends ObjectModel> {
             @Param("children") Collection<String> children);
 
     /**
-     * Deletes rows as necessary to establish the one-to-many relationship
+     * Deletes rows as necessary to modify the one-to-many relationship
      * represented by the RelatedObjectSet between the given parent and
      * children. If the relation for any parent/child pair does not exist,
      * that specific relation is ignored, and deletion proceeds with the


[18/38] guacamole-client git commit: GUACAMOLE-220: Define base interfaces for mapping RelatedObjectSets to the database.

Posted by vn...@apache.org.
GUACAMOLE-220: Define base interfaces for mapping RelatedObjectSets to the database.


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

Branch: refs/heads/master
Commit: 8f06b7a3f9293254a546914dd403e322546fe03b
Parents: a39d863
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Apr 10 12:16:11 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:52 2018 -0700

----------------------------------------------------------------------
 .../auth/jdbc/base/ObjectRelationMapper.java    | 126 +++++++++++
 .../auth/jdbc/base/RelatedObjectSet.java        | 211 +++++++++++++++++++
 2 files changed, 337 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/8f06b7a3/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ObjectRelationMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ObjectRelationMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ObjectRelationMapper.java
new file mode 100644
index 0000000..082db0f
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ObjectRelationMapper.java
@@ -0,0 +1,126 @@
+/*
+ * 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.base;
+
+import java.util.Collection;
+import java.util.Set;
+import org.apache.guacamole.auth.jdbc.user.UserModel;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * Mapper for the relations represented by a particular RelatedObjectSet
+ * implementation.
+ *
+ * @param <ParentModelType>
+ *     The underlying database model of the object on the parent side of the
+ *     one-to-many relationship represented by the RelatedObjectSet mapped by
+ *     this ObjectRelationMapper.
+ */
+public interface ObjectRelationMapper<ParentModelType extends ObjectModel> {
+
+    /**
+     * Inserts rows as necessary to establish the one-to-many relationship
+     * represented by the RelatedObjectSet between the given parent and
+     * children. If the relation for any parent/child pair is already present,
+     * no attempt is made to insert a new row for that relation.
+     *
+     * @param parent
+     *     The model of the object on the parent side of the one-to-many
+     *     relationship represented by the RelatedObjectSet.
+     *
+     * @param children
+     *     The identifiers of the objects on the child side of the one-to-many
+     *     relationship represented by the RelatedObjectSet.
+     *
+     * @return
+     *     The number of rows inserted.
+     */
+    int insert(@Param("parent") ParentModelType parent,
+            @Param("children") Collection<String> children);
+
+    /**
+     * Deletes rows as necessary to establish the one-to-many relationship
+     * represented by the RelatedObjectSet between the given parent and
+     * children. If the relation for any parent/child pair does not exist,
+     * that specific relation is ignored, and deletion proceeds with the
+     * remaining relations.
+     *
+     * @param parent
+     *     The model of the object on the parent side of the one-to-many
+     *     relationship represented by the RelatedObjectSet.
+     *
+     * @param children
+     *     The identifiers of the objects on the child side of the one-to-many
+     *     relationship represented by the RelatedObjectSet.
+     *
+     * @return
+     *     The number of rows deleted.
+     */
+    int delete(@Param("parent") ParentModelType parent,
+            @Param("children") Collection<String> children);
+
+    /**
+     * Retrieves the identifiers of all objects on the child side of the
+     * one-to-many relationship represented by the RelatedObjectSet mapped by
+     * this ObjectRelationMapper. This should only be called on behalf of a
+     * system administrator. If identifiers are needed by a non-administrative
+     * user who must have explicit read rights, use
+     * selectReadableChildIdentifiers() instead.
+     *
+     * @param parent
+     *     The model of the object on the parent side of the one-to-many
+     *     relationship represented by the RelatedObjectSet.
+     *
+     * @return
+     *     A Set containing the identifiers of all objects on the child side
+     *     of the one-to-many relationship.
+     */
+    Set<String> selectChildIdentifiers(@Param("parent") ParentModelType parent);
+
+    /**
+     * Retrieves the identifiers of all objects on the child side of the
+     * one-to-many relationship represented by the RelatedObjectSet mapped by
+     * this ObjectRelationMapper, including only those objects which are
+     * explicitly readable by the given user. If identifiers are needed by a
+     * system administrator (who, by definition, does not need explicit read
+     * rights), use selectChildIdentifiers() instead.
+
+     *
+     * @param user
+     *    The user whose permissions should determine whether an identifier
+     *    is returned.
+     *
+     * @param effectiveGroups
+     *     The identifiers of any known effective groups that should be taken
+     *     into account, such as those defined externally to the database.
+     *
+     * @param parent
+     *     The model of the object on the parent side of the one-to-many
+     *     relationship represented by the RelatedObjectSet.
+     *
+     * @return
+     *     A Set containing the identifiers of all readable objects on the
+     *     child side of the one-to-many relationship.
+     */
+    Set<String> selectReadableChildIdentifiers(@Param("user") UserModel user,
+            @Param("effectiveGroups") Collection<String> effectiveGroups,
+            @Param("parent") ParentModelType parent);
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/8f06b7a3/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java
new file mode 100644
index 0000000..a46cb27
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/RelatedObjectSet.java
@@ -0,0 +1,211 @@
+/*
+ * 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.base;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.GuacamoleSecurityException;
+import org.apache.guacamole.net.auth.permission.ObjectPermission;
+import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
+
+/**
+ * A database implementation of RelatedObjectSet which provides access to a
+ * parent object and corresponding set of objects related to the parent, subject
+ * to object-level permissions. Though the parent and child objects have
+ * specific types, only the parent object's type is enforced through type
+ * parameters, as child objects are represented by identifiers only.
+ *
+ * @param <ParentObjectType>
+ *     The type of object that represents the parent side of the relation.
+ *
+ * @param <ParentModelType>
+ *     The underlying database model of the parent object.
+ */
+public abstract class RelatedObjectSet<ParentObjectType extends ModeledDirectoryObject<ParentModelType>, ParentModelType extends ObjectModel>
+        extends RestrictedObject implements org.apache.guacamole.net.auth.RelatedObjectSet {
+
+    /**
+     * The parent object which shares some arbitrary relation with the objects
+     * within this set.
+     */
+    private ParentObjectType parent;
+
+    /**
+     * Creates a new RelatedObjectSet. The resulting object set must still be
+     * initialized by a call to init().
+     */
+    public RelatedObjectSet() {
+    }
+
+    /**
+     * Initializes this RelatedObjectSet with the current user and the single
+     * object on the parent side of the one-to-many relation represented by the
+     * set.
+     *
+     * @param currentUser
+     *     The user who queried this RelatedObjectSet, and whose permissions
+     *     dictate the access level of all operations performed on this set.
+     *
+     * @param parent
+     *     The parent object which shares some arbitrary relation with the
+     *     objects within this set.
+     */
+    public void init(ModeledAuthenticatedUser currentUser, ParentObjectType parent) {
+        super.init(currentUser);
+        this.parent = parent;
+    }
+
+    /**
+     * Returns the mapper which provides low-level access to the the database
+     * models which drive the relation represented by this RelatedObjectSet.
+     *
+     * @return
+     *     The mapper which provides low-level access to the the database
+     *     models which drive the relation represented by this
+     *     RelatedObjectSet.
+     */
+    protected abstract ObjectRelationMapper<ParentModelType> getObjectRelationMapper();
+
+    /**
+     * Returns the permission set which exposes the effective permissions
+     * available to the current user regarding the objects on the parent side
+     * of the one-to-many relationship represented by this RelatedObjectSet.
+     * Permission inheritance through user groups is taken into account.
+     *
+     * @return
+     *     The permission set which exposes the effective permissions
+     *     available to the current user regarding the objects on the parent
+     *     side of the one-to-many relationship represented by this
+     *     RelatedObjectSet.
+     *
+     * @throws GuacamoleException
+     *     If permission to query permission status is denied.
+     */
+    protected abstract ObjectPermissionSet getParentObjectEffectivePermissionSet()
+            throws GuacamoleException;
+
+    /**
+     * Returns the permission set which exposes the effective permissions
+     * available to the current user regarding the objects on the child side
+     * of the one-to-many relationship represented by this RelatedObjectSet.
+     * Permission inheritance through user groups is taken into account.
+     *
+     * @return
+     *     The permission set which exposes the effective permissions
+     *     available to the current user regarding the objects on the child
+     *     side of the one-to-many relationship represented by this
+     *     RelatedObjectSet.
+     *
+     * @throws GuacamoleException
+     *     If permission to query permission status is denied.
+     */
+    protected abstract ObjectPermissionSet getChildObjectEffectivePermissionSet()
+            throws GuacamoleException;
+
+    /**
+     * Returns whether the current user has permission to alter that status of
+     * the relation between the parent object and the given child objects.
+     *
+     * @param identifiers
+     *     The identifiers of all objects on the child side of the one-to-many
+     *     relation being changed.
+     *
+     * @return
+     *     true if the user has permission to make the described changes,
+     *     false otherwise.
+     *
+     * @throws GuacamoleException
+     *     If permission to query permission status is denied.
+     */
+    private boolean canAlterRelation(Collection<String> identifiers)
+            throws GuacamoleException {
+
+        // System administrators may alter any relations
+        if (getCurrentUser().getUser().isAdministrator())
+            return true;
+
+        // Non-admin users require UPDATE permission on the parent object ...
+        if (!getParentObjectEffectivePermissionSet().hasPermission(
+                ObjectPermission.Type.UPDATE, parent.getIdentifier()))
+            return false;
+
+        // ... as well as UPDATE permission on all child objects being changed
+        Collection<String> accessibleIdentifiers =
+                getChildObjectEffectivePermissionSet().getAccessibleObjects(
+                        Collections.singleton(ObjectPermission.Type.UPDATE),
+                        identifiers);
+
+        return accessibleIdentifiers.size() == identifiers.size();
+
+    }
+
+    @Override
+    public Set<String> getObjects() throws GuacamoleException {
+
+        // Bypass permission checks if the user is a system admin
+        ModeledAuthenticatedUser user = getCurrentUser();
+        if (user.getUser().isAdministrator())
+            return getObjectRelationMapper().selectChildIdentifiers(parent.getModel());
+
+        // Otherwise only return explicitly readable identifiers
+        return getObjectRelationMapper().selectReadableChildIdentifiers(
+                user.getUser().getModel(), user.getEffectiveUserGroups(),
+                parent.getModel());
+
+    }
+
+    @Override
+    public void addObjects(Set<String> identifiers) throws GuacamoleException {
+
+        // Nothing to do if nothing provided
+        if (identifiers.isEmpty())
+            return;
+
+        // Create relations only if permission is granted
+        if (canAlterRelation(identifiers))
+            getObjectRelationMapper().insert(parent.getModel(), identifiers);
+
+        // User lacks permission to add user groups
+        else
+            throw new GuacamoleSecurityException("Permission denied.");
+
+    }
+
+    @Override
+    public void removeObjects(Set<String> identifiers) throws GuacamoleException {
+
+        // Nothing to do if nothing provided
+        if (identifiers.isEmpty())
+            return;
+
+        // Delete relations only if permission is granted
+        if (canAlterRelation(identifiers))
+            getObjectRelationMapper().delete(parent.getModel(), identifiers);
+
+        // User lacks permission to remove user groups
+        else
+            throw new GuacamoleSecurityException("Permission denied.");
+
+    }
+
+}


[27/38] guacamole-client git commit: GUACAMOLE-220: Detect cycles within recursive query. SQL Server cannot deal with cycles on its own.

Posted by vn...@apache.org.
GUACAMOLE-220: Detect cycles within recursive query. SQL Server cannot deal with cycles on its own.

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

Branch: refs/heads/master
Commit: 8399b252cd335d4d0e4b977cd8613e0fe2ed4a4a
Parents: ee35620
Author: Michael Jumper <mj...@apache.org>
Authored: Sun Sep 16 22:33:12 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:53 2018 -0700

----------------------------------------------------------------------
 .../apache/guacamole/auth/jdbc/base/EntityMapper.xml    | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/8399b252/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
index f61463a..a13279e 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
@@ -65,9 +65,10 @@
     <!-- Select names of all effective groups (including inherited) -->
     <select id="selectEffectiveGroupIdentifiers" resultType="string">
 
-        WITH [related_entity] ([entity_id]) AS (
+        WITH [related_entity] ([entity_id], [path]) AS (
             SELECT
-                [guacamole_user_group].entity_id
+                [guacamole_user_group].entity_id,
+                '{' + CAST([guacamole_user_group].entity_id AS VARCHAR(MAX)) + '}'
             FROM [guacamole_user_group]
             JOIN [guacamole_user_group_member] ON [guacamole_user_group].user_group_id = [guacamole_user_group_member].user_group_id
             WHERE
@@ -76,7 +77,8 @@
             <if test="!effectiveGroups.isEmpty()">
                 UNION ALL
                     SELECT
-                        [guacamole_entity].entity_id
+                        [guacamole_entity].entity_id,
+                        '{' + CAST([guacamole_entity].entity_id AS VARCHAR(MAX)) + '}'
                     FROM [guacamole_entity]
                     JOIN [guacamole_user_group] ON [guacamole_user_group].entity_id = [guacamole_entity].entity_id
                     WHERE
@@ -90,12 +92,14 @@
             </if>
             UNION ALL
                 SELECT
-                    [guacamole_user_group].entity_id
+                    [guacamole_user_group].entity_id,
+                    [related_entity].path + '{' + CAST([guacamole_user_group].entity_id AS VARCHAR(MAX)) + '}'
                 FROM [related_entity]
                 JOIN [guacamole_user_group_member] ON [related_entity].entity_id = [guacamole_user_group_member].member_entity_id
                 JOIN [guacamole_user_group] ON [guacamole_user_group].user_group_id = [guacamole_user_group_member].user_group_id
                 WHERE
                     [guacamole_user_group].disabled = 0
+                    AND [related_entity].path NOT LIKE '%{' + CAST([guacamole_user_group].entity_id AS VARCHAR(MAX)) + '}%'
         )
         SELECT DISTINCT name
         FROM [related_entity]


[23/38] guacamole-client git commit: GUACAMOLE-220: Manually recurse through the group membership graph if the database engine does not support recursive queries.

Posted by vn...@apache.org.
GUACAMOLE-220: Manually recurse through the group membership graph if the database engine does not support recursive queries.

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

Branch: refs/heads/master
Commit: 78d5e3b9d746f9f5994d59c46d3d7f953c61a5be
Parents: 48948fc
Author: Michael Jumper <mj...@apache.org>
Authored: Sat Sep 8 01:13:36 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:52 2018 -0700

----------------------------------------------------------------------
 .../guacamole/auth/jdbc/JDBCEnvironment.java    | 11 +++++++++
 .../guacamole/auth/jdbc/base/EntityMapper.java  |  6 +++++
 .../guacamole/auth/jdbc/base/EntityService.java | 25 +++++++++++++++++++-
 .../guacamole/auth/mysql/MySQLEnvironment.java  |  7 +++++-
 .../auth/postgresql/PostgreSQLEnvironment.java  |  5 ++++
 .../auth/sqlserver/SQLServerEnvironment.java    |  7 +++++-
 6 files changed, 58 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/78d5e3b9/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java
index 53935e6..93cc7f7 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java
@@ -137,4 +137,15 @@ public abstract class JDBCEnvironment extends LocalEnvironment {
      */
     public abstract PasswordPolicy getPasswordPolicy();
 
+    /**
+     * Returns whether the database supports recursive queries. Many database
+     * engines support recursive queries through CTEs. If recursive queries are
+     * not supported, queries that are intended to be recursive may need to be
+     * invoked multiple times to retrieve the same data.
+     *
+     * @return
+     *     true if the database supports recursive queries, false otherwise.
+     */
+    public abstract boolean isRecursiveQuerySupported();
+
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/78d5e3b9/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java
index 31efad5..53b0290 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java
@@ -47,6 +47,12 @@ public interface EntityMapper {
      * member, taking into account the given collection of known group
      * memberships which are not necessarily defined within the database.
      *
+     * NOTE: This query is expected to handle recursion through the membership
+     * graph on its own. If the database engine does not support recursive
+     * queries (isRecursiveQuerySupported() of JDBCEnvironment returns false),
+     * then this query will only return one level of depth past the effective
+     * groups given and will need to be invoked multiple times.
+     *
      * @param entity
      *     The entity whose effective groups should be returned.
      *

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/78d5e3b9/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java
index fa71fee..1e40bb0 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java
@@ -22,6 +22,7 @@ package org.apache.guacamole.auth.jdbc.base;
 import com.google.inject.Inject;
 import java.util.Collection;
 import java.util.Set;
+import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
 
 /**
  * Service which provides convenience methods for creating, retrieving, and
@@ -30,6 +31,12 @@ import java.util.Set;
 public class EntityService {
 
     /**
+     * The Guacamole server environment.
+     */
+    @Inject
+    private JDBCEnvironment environment;
+
+    /**
      * Mapper for Entity model objects.
      */
     @Inject
@@ -59,7 +66,23 @@ public class EntityService {
      */
     public Set<String> retrieveEffectiveGroups(ModeledPermissions<? extends EntityModel> entity,
             Collection<String> effectiveGroups) {
-        return entityMapper.selectEffectiveGroupIdentifiers(entity.getModel(), effectiveGroups);
+
+        // Retrieve the effective user groups of the given entity, recursively if possible
+        Set<String> identifiers = entityMapper.selectEffectiveGroupIdentifiers(entity.getModel(), effectiveGroups);
+
+        // If the set of user groups retrieved was not produced recursively,
+        // manually repeat the query to expand the set until all effective
+        // groups have been found
+        if (!environment.isRecursiveQuerySupported() && !identifiers.isEmpty()) {
+            Set<String> previousIdentifiers;
+            do {
+                previousIdentifiers = identifiers;
+                identifiers = entityMapper.selectEffectiveGroupIdentifiers(entity.getModel(), previousIdentifiers);
+            } while (identifiers.size() > previousIdentifiers.size());
+        }
+
+        return identifiers;
+
     }
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/78d5e3b9/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLEnvironment.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLEnvironment.java
index dc676db..062d6df 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLEnvironment.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLEnvironment.java
@@ -225,5 +225,10 @@ public class MySQLEnvironment extends JDBCEnvironment {
     public String getMySQLPassword() throws GuacamoleException {
         return getRequiredProperty(MySQLGuacamoleProperties.MYSQL_PASSWORD);
     }
-    
+
+    @Override
+    public boolean isRecursiveQuerySupported() {
+        return false; // Only very recent versions of MySQL / MariaDB support recursive queries through CTEs
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/78d5e3b9/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLEnvironment.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLEnvironment.java
index da0caea..d5d259e 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLEnvironment.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLEnvironment.java
@@ -242,5 +242,10 @@ public class PostgreSQLEnvironment extends JDBCEnvironment {
     public String getPostgreSQLPassword() throws GuacamoleException {
         return getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_PASSWORD);
     }
+
+    @Override
+    public boolean isRecursiveQuerySupported() {
+        return true; // All versions of PostgreSQL support recursive queries through CTEs
+    }
     
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/78d5e3b9/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerEnvironment.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerEnvironment.java
index 20361e6..03f2cf8 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerEnvironment.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerEnvironment.java
@@ -250,5 +250,10 @@ public class SQLServerEnvironment extends JDBCEnvironment {
             SQLSERVER_DEFAULT_DRIVER
         );
     }
-    
+
+    @Override
+    public boolean isRecursiveQuerySupported() {
+        return true; // All versions of SQL Server support recursive queries through CTEs
+    }
+
 }


[10/38] guacamole-client git commit: GUACAMOLE-220: Update SQL queries to use guacamole_entity table where applicable.

Posted by vn...@apache.org.
GUACAMOLE-220: Update SQL queries to use guacamole_entity table where applicable.


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

Branch: refs/heads/master
Commit: b499092d06b7cd578fb349f41d228d472de39278
Parents: d95e059
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Apr 3 14:23:56 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:51 2018 -0700

----------------------------------------------------------------------
 .../auth/jdbc/connection/ConnectionMapper.xml   | 10 +--
 .../jdbc/connection/ConnectionRecordMapper.xml  | 10 ++-
 .../connectiongroup/ConnectionGroupMapper.xml   | 12 +--
 .../ConnectionGroupPermissionMapper.xml         | 35 ++++-----
 .../permission/ConnectionPermissionMapper.xml   | 35 ++++-----
 .../SharingProfilePermissionMapper.xml          | 35 ++++-----
 .../jdbc/permission/SystemPermissionMapper.xml  | 31 ++++----
 .../jdbc/permission/UserPermissionMapper.xml    | 77 +++++++++++---------
 .../sharingprofile/SharingProfileMapper.xml     |  6 +-
 .../auth/jdbc/user/PasswordRecordMapper.xml     |  3 +-
 .../guacamole/auth/jdbc/user/UserMapper.xml     | 70 ++++++++++++------
 .../auth/jdbc/user/UserRecordMapper.xml         | 23 ++++--
 12 files changed, 188 insertions(+), 159 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/b499092d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
index 0b109f6..c238c78 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
@@ -68,7 +68,7 @@
         SELECT connection_id
         FROM guacamole_connection_permission
         WHERE
-            user_id = #{user.objectID,jdbcType=INTEGER}
+            entity_id = #{user.entityID,jdbcType=INTEGER}
             AND permission = 'READ'
     </select>
 
@@ -89,7 +89,7 @@
         WHERE
             <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer</if>
             <if test="parentIdentifier == null">parent_id IS NULL</if>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND entity_id = #{user.entityID,jdbcType=INTEGER}
             AND permission = 'READ'
     </select>
 
@@ -165,7 +165,7 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+            AND guacamole_connection_permission.entity_id = #{user.entityID,jdbcType=INTEGER}
             AND permission = 'READ'
         GROUP BY guacamole_connection.connection_id;
 
@@ -177,7 +177,7 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND entity_id = #{user.entityID,jdbcType=INTEGER}
             AND permission = 'READ';
 
         SELECT
@@ -191,7 +191,7 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND entity_id = #{user.entityID,jdbcType=INTEGER}
             AND permission = 'READ';
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/b499092d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
index 4545332..b4407bd 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
@@ -79,7 +79,10 @@
             #{record.sharingProfileIdentifier,jdbcType=INTEGER}::integer,
             #{record.sharingProfileName,jdbcType=VARCHAR},
             (SELECT user_id FROM guacamole_user
-             WHERE username = #{record.username,jdbcType=VARCHAR}),
+             JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
+             WHERE
+                   guacamole_entity.name = #{record.username,jdbcType=VARCHAR}
+               AND guacamole_entity.type = 'USER'::guacamole_entity_type),
             #{record.username,jdbcType=VARCHAR},
             #{record.startDate,jdbcType=TIMESTAMP},
             #{record.endDate,jdbcType=TIMESTAMP}
@@ -180,7 +183,10 @@
                 guacamole_connection_history.user_id IN (
                     SELECT user_id
                     FROM guacamole_user
-                    WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
+                    JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
+                    WHERE
+                            POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
+                        AND guacamole_entity.type = 'USER'::guacamole_entity_type
                 )
 
                 OR guacamole_connection_history.connection_id IN (

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/b499092d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
index 7cc4ac7..7e0b188 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
@@ -69,7 +69,7 @@
         SELECT connection_group_id
         FROM guacamole_connection_group_permission
         WHERE
-            user_id = #{user.objectID,jdbcType=INTEGER}
+            entity_id = #{user.entityID,jdbcType=INTEGER}
             AND permission = 'READ'
     </select>
 
@@ -90,7 +90,7 @@
         WHERE
             <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer</if>
             <if test="parentIdentifier == null">parent_id IS NULL</if>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND entity_id = #{user.entityID,jdbcType=INTEGER}
             AND permission = 'READ'
     </select>
 
@@ -161,7 +161,7 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND entity_id = #{user.entityID,jdbcType=INTEGER}
             AND permission = 'READ';
 
         SELECT parent_id, guacamole_connection_group.connection_group_id
@@ -172,7 +172,7 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND entity_id = #{user.entityID,jdbcType=INTEGER}
             AND permission = 'READ';
 
         SELECT parent_id, guacamole_connection.connection_id
@@ -183,7 +183,7 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND entity_id = #{user.entityID,jdbcType=INTEGER}
             AND permission = 'READ';
 
         SELECT
@@ -197,7 +197,7 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND entity_id = #{user.entityID,jdbcType=INTEGER}
             AND permission = 'READ';
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/b499092d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
index 5ab114a..c8ec936 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
@@ -25,24 +25,21 @@
 
     <!-- Result mapper for connection permissions -->
     <resultMap id="ConnectionGroupPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
-        <result column="user_id"             property="userID"           jdbcType="INTEGER"/>
-        <result column="username"            property="username"         jdbcType="VARCHAR"/>
+        <result column="entity_id"           property="entityID"         jdbcType="INTEGER"/>
         <result column="permission"          property="type"             jdbcType="VARCHAR"
                 javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
         <result column="connection_group_id" property="objectIdentifier" jdbcType="INTEGER"/>
     </resultMap>
 
-    <!-- Select all permissions for a given user -->
+    <!-- Select all permissions for a given entity -->
     <select id="select" resultMap="ConnectionGroupPermissionResultMap">
 
         SELECT
-            guacamole_connection_group_permission.user_id,
-            username,
+            entity_id,
             permission,
             connection_group_id
         FROM guacamole_connection_group_permission
-        JOIN guacamole_user ON guacamole_connection_group_permission.user_id = guacamole_user.user_id
-        WHERE guacamole_connection_group_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+        WHERE entity_id = #{entity.entityID,jdbcType=INTEGER}
 
     </select>
 
@@ -50,26 +47,24 @@
     <select id="selectOne" resultMap="ConnectionGroupPermissionResultMap">
 
         SELECT
-            guacamole_connection_group_permission.user_id,
-            username,
+            entity_id,
             permission,
             connection_group_id
         FROM guacamole_connection_group_permission
-        JOIN guacamole_user ON guacamole_connection_group_permission.user_id = guacamole_user.user_id
         WHERE
-            guacamole_connection_group_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+            entity_id = #{entity.entityID,jdbcType=INTEGER}
             AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
             AND connection_group_id = #{identifier,jdbcType=INTEGER}::integer
 
     </select>
 
-    <!-- Select identifiers accessible by the given user for the given permissions -->
+    <!-- Select identifiers accessible by the given entity for the given permissions -->
     <select id="selectAccessibleIdentifiers" resultType="string">
 
         SELECT DISTINCT connection_group_id 
         FROM guacamole_connection_group_permission
         WHERE
-            user_id = #{user.objectID,jdbcType=INTEGER}
+            entity_id = #{entity.entityID,jdbcType=INTEGER}
             AND connection_group_id IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">
@@ -87,10 +82,10 @@
     <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         DELETE FROM guacamole_connection_group_permission
-        WHERE (user_id, permission, connection_group_id) IN
+        WHERE (entity_id, permission, connection_group_id) IN
             <foreach collection="permissions" item="permission"
                      open="(" separator="," close=")">
-                (#{permission.userID,jdbcType=INTEGER},
+                (#{permission.entityID,jdbcType=INTEGER},
                  #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type,
                  #{permission.objectIdentifier,jdbcType=INTEGER}::integer)
             </foreach>
@@ -101,25 +96,25 @@
     <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         INSERT INTO guacamole_connection_group_permission (
-            user_id,
+            entity_id,
             permission,
             connection_group_id
         )
         SELECT DISTINCT
-            permissions.user_id,
+            permissions.entity_id,
             permissions.permission,
             permissions.connection_group_id
         FROM
             <foreach collection="permissions" item="permission"
                      open="(" separator="UNION ALL" close=")">
-                SELECT #{permission.userID,jdbcType=INTEGER}                                 AS user_id,
+                SELECT #{permission.entityID,jdbcType=INTEGER}                               AS entity_id,
                        #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type AS permission,
                        #{permission.objectIdentifier,jdbcType=INTEGER}::integer              AS connection_group_id
             </foreach>
         AS permissions
-        WHERE (user_id, permission, connection_group_id) NOT IN (
+        WHERE (entity_id, permission, connection_group_id) NOT IN (
             SELECT
-                guacamole_connection_group_permission.user_id,
+                guacamole_connection_group_permission.entity_id,
                 guacamole_connection_group_permission.permission,
                 guacamole_connection_group_permission.connection_group_id
             FROM guacamole_connection_group_permission

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/b499092d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
index eed00aa..99eed28 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
@@ -25,24 +25,21 @@
 
     <!-- Result mapper for connection permissions -->
     <resultMap id="ConnectionPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
-        <result column="user_id"       property="userID"           jdbcType="INTEGER"/>
-        <result column="username"      property="username"         jdbcType="VARCHAR"/>
+        <result column="entity_id"     property="entityID"         jdbcType="INTEGER"/>
         <result column="permission"    property="type"             jdbcType="VARCHAR"
                 javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
         <result column="connection_id" property="objectIdentifier" jdbcType="INTEGER"/>
     </resultMap>
 
-    <!-- Select all permissions for a given user -->
+    <!-- Select all permissions for a given entity -->
     <select id="select" resultMap="ConnectionPermissionResultMap">
 
         SELECT
-            guacamole_connection_permission.user_id,
-            username,
+            entity_id,
             permission,
             connection_id
         FROM guacamole_connection_permission
-        JOIN guacamole_user ON guacamole_connection_permission.user_id = guacamole_user.user_id
-        WHERE guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+        WHERE entity_id = #{entity.entityID,jdbcType=INTEGER}
 
     </select>
 
@@ -50,26 +47,24 @@
     <select id="selectOne" resultMap="ConnectionPermissionResultMap">
 
         SELECT
-            guacamole_connection_permission.user_id,
-            username,
+            entity_id,
             permission,
             connection_id
         FROM guacamole_connection_permission
-        JOIN guacamole_user ON guacamole_connection_permission.user_id = guacamole_user.user_id
         WHERE
-            guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+            entity_id = #{entity.entityID,jdbcType=INTEGER}
             AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
             AND connection_id = #{identifier,jdbcType=INTEGER}::integer
 
     </select>
 
-    <!-- Select identifiers accessible by the given user for the given permissions -->
+    <!-- Select identifiers accessible by the given entity for the given permissions -->
     <select id="selectAccessibleIdentifiers" resultType="string">
 
         SELECT DISTINCT connection_id 
         FROM guacamole_connection_permission
         WHERE
-            user_id = #{user.objectID,jdbcType=INTEGER}
+            entity_id = #{entity.entityID,jdbcType=INTEGER}
             AND connection_id IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">
@@ -87,10 +82,10 @@
     <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         DELETE FROM guacamole_connection_permission
-        WHERE (user_id, permission, connection_id) IN
+        WHERE (entity_id, permission, connection_id) IN
             <foreach collection="permissions" item="permission"
                      open="(" separator="," close=")">
-                (#{permission.userID,jdbcType=INTEGER},
+                (#{permission.entityID,jdbcType=INTEGER},
                  #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type,
                  #{permission.objectIdentifier,jdbcType=INTEGER}::integer)
             </foreach>
@@ -101,25 +96,25 @@
     <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         INSERT INTO guacamole_connection_permission (
-            user_id,
+            entity_id,
             permission,
             connection_id
         )
         SELECT DISTINCT
-            permissions.user_id,
+            permissions.entity_id,
             permissions.permission,
             permissions.connection_id
         FROM
             <foreach collection="permissions" item="permission"
                      open="(" separator="UNION ALL" close=")">
-                SELECT #{permission.userID,jdbcType=INTEGER}                                 AS user_id,
+                SELECT #{permission.entityID,jdbcType=INTEGER}                               AS entity_id,
                        #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type AS permission,
                        #{permission.objectIdentifier,jdbcType=INTEGER}::integer              AS connection_id
             </foreach>
         AS permissions
-        WHERE (user_id, permission, connection_id) NOT IN (
+        WHERE (entity_id, permission, connection_id) NOT IN (
             SELECT
-                guacamole_connection_permission.user_id,
+                guacamole_connection_permission.entity_id,
                 guacamole_connection_permission.permission,
                 guacamole_connection_permission.connection_id
             FROM guacamole_connection_permission

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/b499092d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
index faddcdb..73d0ad4 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
@@ -25,24 +25,21 @@
 
     <!-- Result mapper for sharing profile permissions -->
     <resultMap id="SharingProfilePermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
-        <result column="user_id"            property="userID"           jdbcType="INTEGER"/>
-        <result column="username"           property="username"         jdbcType="VARCHAR"/>
+        <result column="entity_id"          property="entityID"         jdbcType="INTEGER"/>
         <result column="permission"         property="type"             jdbcType="VARCHAR"
                 javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
         <result column="sharing_profile_id" property="objectIdentifier" jdbcType="INTEGER"/>
     </resultMap>
 
-    <!-- Select all permissions for a given user -->
+    <!-- Select all permissions for a given entity -->
     <select id="select" resultMap="SharingProfilePermissionResultMap">
 
         SELECT
-            guacamole_sharing_profile_permission.user_id,
-            username,
+            entity_id,
             permission,
             sharing_profile_id
         FROM guacamole_sharing_profile_permission
-        JOIN guacamole_user ON guacamole_sharing_profile_permission.user_id = guacamole_user.user_id
-        WHERE guacamole_sharing_profile_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+        WHERE entity_id = #{entity.entityID,jdbcType=INTEGER}
 
     </select>
 
@@ -50,26 +47,24 @@
     <select id="selectOne" resultMap="SharingProfilePermissionResultMap">
 
         SELECT
-            guacamole_sharing_profile_permission.user_id,
-            username,
+            entity_id,
             permission,
             sharing_profile_id
         FROM guacamole_sharing_profile_permission
-        JOIN guacamole_user ON guacamole_sharing_profile_permission.user_id = guacamole_user.user_id
         WHERE
-            guacamole_sharing_profile_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+            entity_id = #{entity.entityID,jdbcType=INTEGER}
             AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
             AND sharing_profile_id = #{identifier,jdbcType=INTEGER}::integer
 
     </select>
 
-    <!-- Select identifiers accessible by the given user for the given permissions -->
+    <!-- Select identifiers accessible by the given entity for the given permissions -->
     <select id="selectAccessibleIdentifiers" resultType="string">
 
         SELECT DISTINCT sharing_profile_id
         FROM guacamole_sharing_profile_permission
         WHERE
-            user_id = #{user.objectID,jdbcType=INTEGER}
+            entity_id = #{entity.entityID,jdbcType=INTEGER}
             AND sharing_profile_id IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">
@@ -87,10 +82,10 @@
     <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         DELETE FROM guacamole_sharing_profile_permission
-        WHERE (user_id, permission, sharing_profile_id) IN
+        WHERE (entity_id, permission, sharing_profile_id) IN
             <foreach collection="permissions" item="permission"
                      open="(" separator="," close=")">
-                (#{permission.userID,jdbcType=INTEGER},
+                (#{permission.entityID,jdbcType=INTEGER},
                  #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type,
                  #{permission.objectIdentifier,jdbcType=INTEGER}::integer)
             </foreach>
@@ -101,25 +96,25 @@
     <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         INSERT INTO guacamole_sharing_profile_permission (
-            user_id,
+            entity_id,
             permission,
             sharing_profile_id
         )
         SELECT DISTINCT
-            permissions.user_id,
+            permissions.entity_id,
             permissions.permission,
             permissions.sharing_profile_id
         FROM
             <foreach collection="permissions" item="permission"
                      open="(" separator="UNION ALL" close=")">
-                SELECT #{permission.userID,jdbcType=INTEGER}                                 AS user_id,
+                SELECT #{permission.entityID,jdbcType=INTEGER}                               AS entity_id,
                        #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type AS permission,
                        #{permission.objectIdentifier,jdbcType=INTEGER}::integer              AS sharing_profile_id
             </foreach>
         AS permissions
-        WHERE (user_id, permission, sharing_profile_id) NOT IN (
+        WHERE (entity_id, permission, sharing_profile_id) NOT IN (
             SELECT
-                guacamole_sharing_profile_permission.user_id,
+                guacamole_sharing_profile_permission.entity_id,
                 guacamole_sharing_profile_permission.permission,
                 guacamole_sharing_profile_permission.sharing_profile_id
             FROM guacamole_sharing_profile_permission

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/b499092d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
index 96ffb21..5e75891 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
@@ -25,22 +25,19 @@
 
     <!-- Result mapper for system permissions -->
     <resultMap id="SystemPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
-        <result column="user_id"    property="userID"   jdbcType="INTEGER"/>
-        <result column="username"   property="username" jdbcType="VARCHAR"/>
+        <result column="entity_id"  property="entityID" jdbcType="INTEGER"/>
         <result column="permission" property="type"     jdbcType="VARCHAR"
                 javaType="org.apache.guacamole.net.auth.permission.SystemPermission$Type"/>
     </resultMap>
 
-    <!-- Select all permissions for a given user -->
+    <!-- Select all permissions for a given entity -->
     <select id="select" resultMap="SystemPermissionResultMap">
 
         SELECT
-            guacamole_system_permission.user_id,
-            username,
+            entity_id,
             permission
         FROM guacamole_system_permission
-        JOIN guacamole_user ON guacamole_system_permission.user_id = guacamole_user.user_id
-        WHERE guacamole_system_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+        WHERE entity_id = #{entity.entityID,jdbcType=INTEGER}
 
     </select>
 
@@ -48,13 +45,11 @@
     <select id="selectOne" resultMap="SystemPermissionResultMap">
 
         SELECT
-            guacamole_system_permission.user_id,
-            username,
+            entity_id,
             permission
         FROM guacamole_system_permission
-        JOIN guacamole_user ON guacamole_system_permission.user_id = guacamole_user.user_id
         WHERE
-            guacamole_system_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+            entity_id = #{entity.entityID,jdbcType=INTEGER}
             AND permission = #{type,jdbcType=VARCHAR}::guacamole_system_permission_type
 
     </select>
@@ -63,10 +58,10 @@
     <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
 
         DELETE FROM guacamole_system_permission
-        WHERE (user_id, permission) IN
+        WHERE (entity_id, permission) IN
             <foreach collection="permissions" item="permission"
                      open="(" separator="," close=")">
-                (#{permission.userID,jdbcType=INTEGER},
+                (#{permission.entityID,jdbcType=INTEGER},
                  #{permission.type,jdbcType=VARCHAR}::guacamole_system_permission_type)
             </foreach>
 
@@ -76,22 +71,22 @@
     <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
 
         INSERT INTO guacamole_system_permission (
-            user_id,
+            entity_id,
             permission
         )
         SELECT DISTINCT
-            permissions.user_id,
+            permissions.entity_id,
             permissions.permission
         FROM
             <foreach collection="permissions" item="permission"
                      open="(" separator="UNION ALL" close=")">
-                SELECT #{permission.userID,jdbcType=INTEGER}                                 AS user_id,
+                SELECT #{permission.entityID,jdbcType=INTEGER}                               AS entity_id,
                        #{permission.type,jdbcType=VARCHAR}::guacamole_system_permission_type AS permission
             </foreach>
         AS permissions
-        WHERE (user_id, permission) NOT IN (
+        WHERE (entity_id, permission) NOT IN (
             SELECT
-                guacamole_system_permission.user_id,
+                guacamole_system_permission.entity_id,
                 guacamole_system_permission.permission
             FROM guacamole_system_permission
         );

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/b499092d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
index 0126ae5..d6680ea 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
@@ -25,25 +25,25 @@
 
     <!-- Result mapper for user permissions -->
     <resultMap id="UserPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
-        <result column="user_id"           property="userID"           jdbcType="INTEGER"/>
-        <result column="username"          property="username"         jdbcType="VARCHAR"/>
+        <result column="entity_id"         property="entityID"         jdbcType="INTEGER"/>
         <result column="permission"        property="type"             jdbcType="VARCHAR"
                 javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
-        <result column="affected_username" property="objectIdentifier" jdbcType="INTEGER"/>
+        <result column="affected_name"     property="objectIdentifier" jdbcType="INTEGER"/>
     </resultMap>
 
-    <!-- Select all permissions for a given user -->
+    <!-- Select all permissions for a given entity -->
     <select id="select" resultMap="UserPermissionResultMap">
 
         SELECT
-            guacamole_user_permission.user_id,
-            guacamole_user.username,
+            guacamole_user_permission.entity_id,
             permission,
-            affected.username AS affected_username
+            affected_entity.name AS affected_name
         FROM guacamole_user_permission
-        JOIN guacamole_user          ON guacamole_user_permission.user_id          = guacamole_user.user_id
-        JOIN guacamole_user affected ON guacamole_user_permission.affected_user_id = affected.user_id
-        WHERE guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+        JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
+        JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
+        WHERE
+            guacamole_user_permission.entity_id = #{entity.entityID,jdbcType=INTEGER}
+            AND affected_entity.type = 'USER'::guacamole_entity_type
 
     </select>
 
@@ -51,38 +51,40 @@
     <select id="selectOne" resultMap="UserPermissionResultMap">
 
         SELECT
-            guacamole_user_permission.user_id,
-            guacamole_user.username,
+            guacamole_user_permission.entity_id,
             permission,
-            affected.username AS affected_username
+            affected_entity.name AS affected_name
         FROM guacamole_user_permission
-        JOIN guacamole_user          ON guacamole_user_permission.user_id          = guacamole_user.user_id
-        JOIN guacamole_user affected ON guacamole_user_permission.affected_user_id = affected.user_id
+        JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
+        JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
         WHERE
-            guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+            guacamole_user_permission.entity_id = #{entity.entityID,jdbcType=INTEGER}
             AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type
-            AND affected.username = #{identifier,jdbcType=INTEGER}
+            AND affected_entity.name = #{identifier,jdbcType=VARCHAR}
+            AND affected_entity.type = 'USER'::guacamole_entity_type
 
     </select>
 
-    <!-- Select identifiers accessible by the given user for the given permissions -->
+    <!-- Select identifiers accessible by the given entity for the given permissions -->
     <select id="selectAccessibleIdentifiers" resultType="string">
 
-        SELECT DISTINCT username
+        SELECT DISTINCT affected_entity.name
         FROM guacamole_user_permission
-        JOIN guacamole_user ON guacamole_user_permission.affected_user_id = guacamole_user.user_id
+        JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
+        JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
         WHERE
-            guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
-            AND username IN
+            guacamole_user_permission.entity_id = #{entity.entityID,jdbcType=INTEGER}
+            AND affected_entity.name IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">
-                    #{identifier,jdbcType=INTEGER}
+                    #{identifier,jdbcType=VARCHAR}
                 </foreach>
             AND permission IN
                 <foreach collection="permissions" item="permission"
                          open="(" separator="," close=")">
                     #{permission,jdbcType=VARCHAR}::guacamole_object_permission_type
                 </foreach>
+            AND affected_entity.type = 'USER'::guacamole_entity_type
 
     </select>
 
@@ -90,16 +92,18 @@
     <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         DELETE FROM guacamole_user_permission
-        USING guacamole_user affected
+        USING guacamole_user affected_user, guacamole_entity affected_entity
         WHERE
-            guacamole_user_permission.affected_user_id = affected.user_id
-            AND (guacamole_user_permission.user_id, permission, affected.username) IN
+            guacamole_user_permission.affected_user_id = affected_user.user_id
+            AND affected_user.entity_id = affected_entity.entity_id
+            AND (guacamole_user_permission.entity_id, permission, affected_entity.name) IN
                 <foreach collection="permissions" item="permission"
                          open="(" separator="," close=")">
-                    (#{permission.userID,jdbcType=INTEGER},
+                    (#{permission.entityID,jdbcType=INTEGER},
                      #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type,
                      #{permission.objectIdentifier,jdbcType=INTEGER})
                 </foreach>
+            AND affected_entity.type = 'USER'::guacamole_entity_type
 
     </delete>
 
@@ -107,26 +111,29 @@
     <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         INSERT INTO guacamole_user_permission (
-            user_id,
+            entity_id,
             permission,
             affected_user_id
         )
         SELECT DISTINCT
-            permissions.user_id,
+            permissions.entity_id,
             permissions.permission,
-            guacamole_user.user_id
+            affected_user.user_id
         FROM
             <foreach collection="permissions" item="permission"
                      open="(" separator="UNION ALL" close=")">
-                SELECT #{permission.userID,jdbcType=INTEGER}                                 AS user_id,
+                SELECT #{permission.entityID,jdbcType=INTEGER}                               AS entity_id,
                        #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type AS permission,
-                       #{permission.objectIdentifier,jdbcType=INTEGER}                       AS username
+                       #{permission.objectIdentifier,jdbcType=VARCHAR}::text                 AS affected_name
             </foreach>
         AS permissions
-        JOIN guacamole_user ON guacamole_user.username = permissions.username
-        WHERE (permissions.user_id, permissions.permission, guacamole_user.user_id) NOT IN (
+        JOIN guacamole_entity affected_entity ON
+                affected_entity.name = permissions.affected_name
+            AND affected_entity.type = 'USER'::guacamole_entity_type
+        JOIN guacamole_user affected_user ON affected_user.entity_id = affected_entity.entity_id
+        WHERE (permissions.entity_id, permissions.permission, affected_user.user_id) NOT IN (
             SELECT
-                guacamole_user_permission.user_id,
+                guacamole_user_permission.entity_id,
                 guacamole_user_permission.permission,
                 guacamole_user_permission.affected_user_id
             FROM guacamole_user_permission

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/b499092d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
index 801d6e3..66bd701 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
@@ -52,7 +52,7 @@
         SELECT sharing_profile_id
         FROM guacamole_sharing_profile_permission
         WHERE
-            user_id = #{user.objectID,jdbcType=INTEGER}
+            entity_id = #{user.entityID,jdbcType=INTEGER}
             AND permission = 'READ'
     </select>
 
@@ -99,7 +99,7 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND entity_id = #{user.entityID,jdbcType=INTEGER}
             AND permission = 'READ';
 
         SELECT
@@ -113,7 +113,7 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND entity_id = #{user.entityID,jdbcType=INTEGER}
             AND permission = 'READ';
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/b499092d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml
index 41591fa..e9c857a 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml
@@ -41,8 +41,9 @@
             guacamole_user_password_history.password_date
         FROM guacamole_user_password_history
         JOIN guacamole_user ON guacamole_user_password_history.user_id = guacamole_user.user_id
+        JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
         WHERE
-            guacamole_user.username = #{username,jdbcType=VARCHAR}
+            guacamole_entity.name = #{username,jdbcType=VARCHAR}
         ORDER BY
             guacamole_user_password_history.password_date DESC
         LIMIT #{maxHistorySize}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/b499092d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
index e183fe2..796962d 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
@@ -28,7 +28,8 @@
 
         <!-- User properties -->
         <id     column="user_id"             property="objectID"           jdbcType="INTEGER"/>
-        <result column="username"            property="identifier"         jdbcType="VARCHAR"/>
+        <result column="entity_id"           property="entityID"           jdbcType="INTEGER"/>
+        <result column="name"                property="identifier"         jdbcType="VARCHAR"/>
         <result column="password_hash"       property="passwordHash"       jdbcType="BINARY"/>
         <result column="password_salt"       property="passwordSalt"       jdbcType="BINARY"/>
         <result column="password_date"       property="passwordDate"       jdbcType="TIMESTAMP"/>
@@ -57,17 +58,20 @@
 
     <!-- Select all usernames -->
     <select id="selectIdentifiers" resultType="string">
-        SELECT username
-        FROM guacamole_user
+        SELECT name
+        FROM guacamole_entity
+        WHERE guacamole_entity.type = 'USER'::guacamole_entity_type
     </select>
 
     <!-- Select usernames of all readable users -->
     <select id="selectReadableIdentifiers" resultType="string">
-        SELECT username
+        SELECT guacamole_entity.name
         FROM guacamole_user
+        JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
         JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
         WHERE
-            guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+            guacamole_user_permission.entity_id = #{user.entityID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER'::guacamole_entity_type
             AND permission = 'READ'
     </select>
 
@@ -77,7 +81,8 @@
 
         SELECT
             guacamole_user.user_id,
-            guacamole_user.username,
+            guacamole_entity.entity_id,
+            guacamole_entity.name,
             password_hash,
             password_salt,
             password_date,
@@ -94,13 +99,15 @@
             organizational_role,
             MAX(start_date) AS last_active
         FROM guacamole_user
+        JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
         LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
-        WHERE guacamole_user.username IN
+        WHERE guacamole_entity.name IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
-        GROUP BY guacamole_user.user_id;
+            AND guacamole_entity.type = 'USER'::guacamole_entity_type
+        GROUP BY guacamole_user.user_id, guacamole_entity.entity_id;
 
         SELECT
             guacamole_user_attribute.user_id,
@@ -108,11 +115,13 @@
             guacamole_user_attribute.attribute_value
         FROM guacamole_user_attribute
         JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
-        WHERE username IN
+        JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
+        WHERE guacamole_entity.name IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
-            </foreach>;
+            </foreach>
+            AND guacamole_entity.type = 'USER'::guacamole_entity_type;
 
     </select>
 
@@ -122,7 +131,8 @@
 
         SELECT
             guacamole_user.user_id,
-            guacamole_user.username,
+            guacamole_entity.entity_id,
+            guacamole_entity.name,
             password_hash,
             password_salt,
             password_date,
@@ -139,16 +149,18 @@
             organizational_role,
             MAX(start_date) AS last_active
         FROM guacamole_user
+        JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
         JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
         LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
-        WHERE guacamole_user.username IN
+        WHERE guacamole_entity.name IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
-            AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER'::guacamole_entity_type
+            AND guacamole_user_permission.entity_id = #{user.entityID,jdbcType=INTEGER}
             AND permission = 'READ'
-        GROUP BY guacamole_user.user_id;
+        GROUP BY guacamole_user.user_id, guacamole_entity.entity_id;
 
         SELECT
             guacamole_user_attribute.user_id,
@@ -156,13 +168,15 @@
             guacamole_user_attribute.attribute_value
         FROM guacamole_user_attribute
         JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
+        JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
         JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
-        WHERE username IN
+        WHERE guacamole_entity.name IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
-            AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER'::guacamole_entity_type
+            AND guacamole_user_permission.entity_id = #{user.entityID,jdbcType=INTEGER}
             AND permission = 'READ';
 
     </select>
@@ -173,7 +187,8 @@
 
         SELECT
             guacamole_user.user_id,
-            guacamole_user.username,
+            guacamole_entity.entity_id,
+            guacamole_entity.name,
             password_hash,
             password_salt,
             password_date,
@@ -190,10 +205,12 @@
             organizational_role,
             MAX(start_date) AS last_active
         FROM guacamole_user
+        JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
         LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
         WHERE
-            guacamole_user.username = #{username,jdbcType=VARCHAR}
-        GROUP BY guacamole_user.user_id;
+            guacamole_entity.name = #{username,jdbcType=VARCHAR}
+            AND guacamole_entity.type = 'USER'::guacamole_entity_type
+        GROUP BY guacamole_user.user_id, guacamole_entity.entity_id;
 
         SELECT
             guacamole_user_attribute.user_id,
@@ -201,14 +218,19 @@
             guacamole_user_attribute.attribute_value
         FROM guacamole_user_attribute
         JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
-        WHERE username = #{username,jdbcType=VARCHAR};
+        JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
+        WHERE
+            guacamole_entity.name = #{username,jdbcType=VARCHAR}
+            AND guacamole_entity.type = 'USER'::guacamole_entity_type
 
     </select>
 
     <!-- Delete single user by username -->
     <delete id="delete">
-        DELETE FROM guacamole_user
-        WHERE username = #{identifier,jdbcType=VARCHAR}
+        DELETE FROM guacamole_entity
+        WHERE
+            name = #{identifier,jdbcType=VARCHAR}
+            AND type = 'USER'::guacamole_entity_type
     </delete>
 
     <!-- Insert single user -->
@@ -216,7 +238,7 @@
             parameterType="org.apache.guacamole.auth.jdbc.user.UserModel">
 
         INSERT INTO guacamole_user (
-            username,
+            entity_id,
             password_hash,
             password_salt,
             password_date,
@@ -233,7 +255,7 @@
             organizational_role
         )
         VALUES (
-            #{object.identifier,jdbcType=VARCHAR},
+            #{object.entityID,jdbcType=VARCHAR},
             #{object.passwordHash,jdbcType=BINARY},
             #{object.passwordSalt,jdbcType=BINARY},
             #{object.passwordDate,jdbcType=TIMESTAMP},

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/b499092d/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
index 014b38a..20cb2a8 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
@@ -44,8 +44,9 @@
             guacamole_user_history.end_date
         FROM guacamole_user_history
         JOIN guacamole_user ON guacamole_user_history.user_id = guacamole_user.user_id
+        JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
         WHERE
-            guacamole_user.username = #{username,jdbcType=VARCHAR}
+            guacamole_entity.name = #{username,jdbcType=VARCHAR}
         ORDER BY
             guacamole_user_history.start_date DESC,
             guacamole_user_history.end_date DESC
@@ -66,7 +67,10 @@
         VALUES (
             #{record.remoteHost,jdbcType=VARCHAR},
             (SELECT user_id FROM guacamole_user
-             WHERE username = #{record.username,jdbcType=VARCHAR}),
+             JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
+             WHERE
+                   guacamole_entity.name = #{record.username,jdbcType=VARCHAR}
+               AND guacamole_entity.type = 'USER'::guacamole_entity_type),
             #{record.username,jdbcType=VARCHAR},
             #{record.startDate,jdbcType=TIMESTAMP},
             #{record.endDate,jdbcType=TIMESTAMP}
@@ -79,7 +83,10 @@
         UPDATE guacamole_user_history
         SET remote_host = #{record.remoteHost,jdbcType=VARCHAR},
             user_id     = (SELECT user_id FROM guacamole_user
-                           WHERE username = #{record.username,jdbcType=VARCHAR}),
+                           JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
+                           WHERE
+                                   guacamole_entity.name = #{record.username,jdbcType=VARCHAR}
+                               AND guacamole_entity.type = 'USER'::guacamole_entity_type),
             username    = #{record.username,jdbcType=VARCHAR},
             start_date  = #{record.startDate,jdbcType=TIMESTAMP},
             end_date    = #{record.endDate,jdbcType=TIMESTAMP}
@@ -105,7 +112,10 @@
                 guacamole_user_history.user_id IN (
                     SELECT user_id
                     FROM guacamole_user
-                    WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
+                    JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
+                    WHERE
+                            POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
+                        AND guacamole_entity.type = 'USER'::guacamole_entity_type),
                 )
 
                 <if test="term.startDate != null and term.endDate != null">
@@ -157,7 +167,10 @@
                 guacamole_user_history.user_id IN (
                     SELECT user_id
                     FROM guacamole_user
-                    WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
+                    JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
+                    WHERE
+                            POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
+                        AND guacamole_entity.type = 'USER'::guacamole_entity_type
                 )
 
                 <if test="term.startDate != null and term.endDate != null">


[24/38] guacamole-client git commit: GUACAMOLE-220: Add missing JDBC-specific USER_GROUP_ATTRIBUTES translation strings.

Posted by vn...@apache.org.
GUACAMOLE-220: Add missing JDBC-specific USER_GROUP_ATTRIBUTES translation strings.


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

Branch: refs/heads/master
Commit: 48948fc24565f28ba4c98974332364022576f538
Parents: 2999c56
Author: Michael Jumper <mj...@apache.org>
Authored: Thu Apr 19 23:50:19 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:52 2018 -0700

----------------------------------------------------------------------
 .../src/main/resources/translations/en.json                  | 8 ++++++++
 1 file changed, 8 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/48948fc2/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/resources/translations/en.json
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/resources/translations/en.json b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/resources/translations/en.json
index ff14842..5520a81 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/resources/translations/en.json
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/resources/translations/en.json
@@ -100,6 +100,14 @@
         "SECTION_HEADER_RESTRICTIONS" : "Account Restrictions",
         "SECTION_HEADER_PROFILE"      : "Profile"
 
+    },
+
+    "USER_GROUP_ATTRIBUTES" : {
+
+        "FIELD_HEADER_DISABLED" : "@:USER_ATTRIBUTES.FIELD_HEADER_DISABLED",
+
+        "SECTION_HEADER_RESTRICTIONS" : "@:USER_ATTRIBUTES.SECTION_HEADER_RESTRICTIONS"
+
     }
 
 }


[31/38] guacamole-client git commit: GUACAMOLE-220: Clarify group rename validation logic.

Posted by vn...@apache.org.
GUACAMOLE-220: Clarify group rename validation logic.

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

Branch: refs/heads/master
Commit: a552d88c5481accaf135c5315a994cad0944fbf7
Parents: fedcceb
Author: Michael Jumper <mj...@apache.org>
Authored: Thu Sep 27 20:06:18 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Thu Sep 27 20:06:18 2018 -0700

----------------------------------------------------------------------
 .../auth/jdbc/usergroup/UserGroupService.java         | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a552d88c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupService.java
index dfe1ef5..0f4a216 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/UserGroupService.java
@@ -162,19 +162,15 @@ public class UserGroupService extends ModeledDirectoryObjectService<ModeledUserG
 
         super.beforeUpdate(user, object, model);
         
-        // Username must not be blank
+        // Group names must not be blank
         if (model.getIdentifier() == null || model.getIdentifier().trim().isEmpty())
             throw new GuacamoleClientException("The group name must not be blank.");
         
-        // Check whether such a group is already present
+        // Do not allow groups to be renamed if the name collides with that of
+        // another, existing group
         UserGroupModel existing = userGroupMapper.selectOne(model.getIdentifier());
-        if (existing != null) {
-
-            // Do not rename to existing user group
-            if (!existing.getObjectID().equals(model.getObjectID()))
-                throw new GuacamoleClientException("Group \"" + model.getIdentifier() + "\" already exists.");
-            
-        }
+        if (existing != null && !existing.getObjectID().equals(model.getObjectID()))
+            throw new GuacamoleClientException("Group \"" + model.getIdentifier() + "\" already exists.");
 
     }
 


[02/38] guacamole-client git commit: GUACAMOLE-220: Refactor handling of JDBC permissions to abstract away users vs. user groups.

Posted by vn...@apache.org.
GUACAMOLE-220: Refactor handling of JDBC permissions to abstract away users vs. user groups.


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

Branch: refs/heads/master
Commit: 69f58c8ca314c44822e0eaab354b5f722a01ac89
Parents: 14d10fb
Author: Michael Jumper <mj...@apache.org>
Authored: Sat Apr 7 19:10:38 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:51 2018 -0700

----------------------------------------------------------------------
 .../jdbc/JDBCAuthenticationProviderModule.java  |   2 +
 .../ActiveConnectionPermissionService.java      |  37 +--
 .../guacamole/auth/jdbc/base/EntityMapper.java  |  22 ++
 .../guacamole/auth/jdbc/base/EntityService.java |  65 +++++
 .../auth/jdbc/base/ModeledPermissions.java      | 266 +++++++++++++++++++
 .../permission/AbstractPermissionService.java   |  59 +++-
 .../ConnectionGroupPermissionService.java       |  11 +-
 .../permission/ConnectionPermissionService.java |  11 +-
 .../ModeledObjectPermissionService.java         |  68 ++---
 .../permission/ModeledPermissionService.java    |  37 +--
 .../permission/ObjectPermissionService.java     |  37 +--
 .../jdbc/permission/ObjectPermissionSet.java    |  42 +--
 .../auth/jdbc/permission/PermissionService.java |  66 ++---
 .../SharingProfilePermissionService.java        |  11 +-
 .../permission/SystemPermissionService.java     |  42 +--
 .../jdbc/permission/SystemPermissionSet.java    |  40 +--
 .../jdbc/permission/UserPermissionService.java  |  11 +-
 .../guacamole/auth/jdbc/user/ModeledUser.java   | 191 +------------
 .../guacamole/auth/jdbc/user/UserMapper.java    |  22 --
 .../guacamole/auth/jdbc/user/UserService.java   |  28 --
 .../guacamole/auth/jdbc/base/EntityMapper.xml   |  38 +++
 .../guacamole/auth/jdbc/user/UserMapper.xml     |  38 ---
 22 files changed, 673 insertions(+), 471 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
index 17dfc5d..48c95c7 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java
@@ -60,6 +60,7 @@ import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissio
 import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionService;
 import org.apache.guacamole.auth.jdbc.activeconnection.TrackedActiveConnection;
 import org.apache.guacamole.auth.jdbc.base.EntityMapper;
+import org.apache.guacamole.auth.jdbc.base.EntityService;
 import org.apache.guacamole.auth.jdbc.connection.ConnectionParameterMapper;
 import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionMapper;
 import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService;
@@ -161,6 +162,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule {
         bind(ConnectionPermissionService.class);
         bind(ConnectionSharingService.class);
         bind(ConnectionService.class);
+        bind(EntityService.class);
         bind(GuacamoleTunnelService.class).to(RestrictedGuacamoleTunnelService.class);
         bind(PasswordEncryptionService.class).to(SHA256PasswordEncryptionService.class);
         bind(PasswordPolicyService.class);

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java
index a0511b8..e7cbd5d 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java
@@ -27,12 +27,13 @@ import java.util.HashSet;
 import java.util.Set;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.GuacamoleSecurityException;
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
+import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
 import org.apache.guacamole.auth.jdbc.permission.AbstractPermissionService;
 import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionService;
 import org.apache.guacamole.auth.jdbc.tunnel.ActiveConnectionRecord;
 import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
-import org.apache.guacamole.auth.jdbc.user.ModeledUser;
 import org.apache.guacamole.net.auth.permission.ObjectPermission;
 import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
 
@@ -58,12 +59,13 @@ public class ActiveConnectionPermissionService
 
     @Override
     public boolean hasPermission(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, ObjectPermission.Type type,
-            String identifier, Set<String> effectiveGroups) throws GuacamoleException {
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            ObjectPermission.Type type, String identifier,
+            Set<String> effectiveGroups) throws GuacamoleException {
 
         // Retrieve permissions
         Set<ObjectPermission> permissions = retrievePermissions(user,
-                targetUser, effectiveGroups);
+                targetEntity, effectiveGroups);
 
         // Permission is granted if retrieved permissions contains the
         // requested permission
@@ -74,14 +76,14 @@ public class ActiveConnectionPermissionService
 
     @Override
     public Set<ObjectPermission> retrievePermissions(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, Set<String> effectiveGroups)
-            throws GuacamoleException {
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            Set<String> effectiveGroups) throws GuacamoleException {
 
         // Retrieve permissions only if allowed
-        if (canReadPermissions(user, targetUser)) {
+        if (canReadPermissions(user, targetEntity)) {
 
             // Only administrators may access active connections
-            boolean isAdmin = targetUser.isAdministrator();
+            boolean isAdmin = targetEntity.isAdministrator();
 
             // Get all active connections
             Collection<ActiveConnectionRecord> records = tunnelService.getActiveConnections(user);
@@ -110,11 +112,12 @@ public class ActiveConnectionPermissionService
 
     @Override
     public Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, Collection<ObjectPermission.Type> permissionTypes,
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            Collection<ObjectPermission.Type> permissionTypes,
             Collection<String> identifiers, Set<String> effectiveGroups)
             throws GuacamoleException {
 
-        Set<ObjectPermission> permissions = retrievePermissions(user, targetUser, effectiveGroups);
+        Set<ObjectPermission> permissions = retrievePermissions(user, targetEntity, effectiveGroups);
         Collection<String> accessibleObjects = new ArrayList<String>(permissions.size());
 
         // For each identifier/permission combination
@@ -137,12 +140,12 @@ public class ActiveConnectionPermissionService
 
     @Override
     public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, Set<String> effectiveGroups)
-            throws GuacamoleException {
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            Set<String> effectiveGroups) throws GuacamoleException {
     
-        // Create permission set for requested user
+        // Create permission set for requested entity
         ActiveConnectionPermissionSet permissionSet = activeConnectionPermissionSetProvider.get();
-        permissionSet.init(user, targetUser, effectiveGroups);
+        permissionSet.init(user, targetEntity, effectiveGroups);
 
         return permissionSet;
  
@@ -150,7 +153,8 @@ public class ActiveConnectionPermissionService
 
     @Override
     public void createPermissions(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, Collection<ObjectPermission> permissions)
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            Collection<ObjectPermission> permissions)
             throws GuacamoleException {
 
         // Creating active connection permissions is not implemented
@@ -160,7 +164,8 @@ public class ActiveConnectionPermissionService
 
     @Override
     public void deletePermissions(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, Collection<ObjectPermission> permissions)
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            Collection<ObjectPermission> permissions)
             throws GuacamoleException {
 
         // Deleting active connection permissions is not implemented

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java
index 14657ce..31efad5 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java
@@ -19,6 +19,8 @@
 
 package org.apache.guacamole.auth.jdbc.base;
 
+import java.util.Collection;
+import java.util.Set;
 import org.apache.ibatis.annotations.Param;
 
 /**
@@ -40,4 +42,24 @@ public interface EntityMapper {
      */
     int insert(@Param("entity") EntityModel entity);
 
+    /**
+     * Returns the set of all group identifiers of which the given entity is a
+     * member, taking into account the given collection of known group
+     * memberships which are not necessarily defined within the database.
+     *
+     * @param entity
+     *     The entity whose effective groups should be returned.
+     *
+     * @param effectiveGroups
+     *     The identifiers of any known effective groups that should be taken
+     *     into account, such as those defined externally to the database.
+     *
+     * @return
+     *     The set of identifiers of all groups that the given entity is a
+     *     member of, including those where membership is inherited through
+     *     membership in other groups.
+     */
+    Set<String> selectEffectiveGroupIdentifiers(@Param("entity") EntityModel entity,
+            @Param("effectiveGroups") Collection<String> effectiveGroups);
+
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java
new file mode 100644
index 0000000..fa71fee
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.base;
+
+import com.google.inject.Inject;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * Service which provides convenience methods for creating, retrieving, and
+ * manipulating entities.
+ */
+public class EntityService {
+
+    /**
+     * Mapper for Entity model objects.
+     */
+    @Inject
+    private EntityMapper entityMapper;
+
+    /**
+     * Returns the set of all group identifiers of which the given entity is a
+     * member, taking into account the given collection of known group
+     * memberships which are not necessarily defined within the database.
+     * 
+     * Note that group visibility with respect to the queried entity is NOT
+     * taken into account. If the entity is a member of a group, the identifier
+     * of that group will be included in the returned set even if the current
+     * user lacks "READ" permission for that group.
+     *
+     * @param entity
+     *     The entity whose effective groups should be returned.
+     *
+     * @param effectiveGroups
+     *     The identifiers of any known effective groups that should be taken
+     *     into account, such as those defined externally to the database.
+     *
+     * @return
+     *     The set of identifiers of all groups that the given entity is a
+     *     member of, including those where membership is inherited through
+     *     membership in other groups.
+     */
+    public Set<String> retrieveEffectiveGroups(ModeledPermissions<? extends EntityModel> entity,
+            Collection<String> effectiveGroups) {
+        return entityMapper.selectEffectiveGroupIdentifiers(entity.getModel(), effectiveGroups);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledPermissions.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledPermissions.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledPermissions.java
new file mode 100644
index 0000000..2f7808d
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledPermissions.java
@@ -0,0 +1,266 @@
+/*
+ * 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.base;
+
+import com.google.inject.Inject;
+import java.util.Collections;
+import java.util.Set;
+import org.apache.guacamole.auth.jdbc.permission.SystemPermissionService;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.activeconnection.ActiveConnectionPermissionService;
+import org.apache.guacamole.auth.jdbc.permission.ConnectionGroupPermissionService;
+import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionService;
+import org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionService;
+import org.apache.guacamole.auth.jdbc.permission.UserPermissionService;
+import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
+import org.apache.guacamole.net.auth.Permissions;
+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.net.auth.simple.SimpleObjectPermissionSet;
+
+/**
+ * An implementation of the base Permissions interface which is common to both
+ * Users and UserGroups, backed by a database model.
+ *
+ * @param <ModelType>
+ *     The type of model object that corresponds to this object.
+ */
+public abstract class ModeledPermissions<ModelType extends EntityModel>
+        extends ModeledDirectoryObject<ModelType> implements Permissions {
+
+    /**
+     * Service for retrieving entity details.
+     */
+    @Inject
+    private EntityService entityService;
+
+    /**
+     * Service for retrieving system permissions.
+     */
+    @Inject
+    private SystemPermissionService systemPermissionService;
+
+    /**
+     * Service for retrieving connection permissions.
+     */
+    @Inject
+    private ConnectionPermissionService connectionPermissionService;
+
+    /**
+     * Service for retrieving connection group permissions.
+     */
+    @Inject
+    private ConnectionGroupPermissionService connectionGroupPermissionService;
+
+    /**
+     * Service for retrieving sharing profile permissions.
+     */
+    @Inject
+    private SharingProfilePermissionService sharingProfilePermissionService;
+
+    /**
+     * Service for retrieving active connection permissions.
+     */
+    @Inject
+    private ActiveConnectionPermissionService activeConnectionPermissionService;
+
+    /**
+     * Service for retrieving user permissions.
+     */
+    @Inject
+    private UserPermissionService userPermissionService;
+
+    /**
+     * Returns whether the underlying entity is a user. Entities may be either
+     * users or user groups.
+     *
+     * @return
+     *     true if the underlying entity is a user, false otherwise.
+     */
+    public boolean isUser() {
+        return getModel().getEntityType() == EntityType.USER;
+    }
+
+    /**
+     * Returns whether the underlying entity is a user group. Entities may be
+     * either users or user groups.
+     *
+     * @return
+     *     true if the underlying entity is a user group, false otherwise.
+     */
+    public boolean isUserGroup() {
+        return getModel().getEntityType() == EntityType.USER_GROUP;
+    }
+
+    /**
+     * Returns whether this entity is a system administrator, and thus is not
+     * restricted by permissions, taking into account permission inheritance
+     * via user groups.
+     *
+     * @return
+     *    true if this entity is a system administrator, false otherwise.
+     *
+     * @throws GuacamoleException
+     *    If an error occurs while determining the entity's system administrator
+     *    status.
+     */
+    public boolean isAdministrator() throws GuacamoleException {
+        SystemPermissionSet systemPermissionSet = getEffective().getSystemPermissions();
+        return systemPermissionSet.hasPermission(SystemPermission.Type.ADMINISTER);
+    }
+
+    @Override
+    public SystemPermissionSet getSystemPermissions()
+            throws GuacamoleException {
+        return systemPermissionService.getPermissionSet(getCurrentUser(), this,
+                Collections.<String>emptySet());
+    }
+
+    @Override
+    public ObjectPermissionSet getConnectionPermissions()
+            throws GuacamoleException {
+        return connectionPermissionService.getPermissionSet(getCurrentUser(),
+                this, Collections.<String>emptySet());
+    }
+
+    @Override
+    public ObjectPermissionSet getConnectionGroupPermissions()
+            throws GuacamoleException {
+        return connectionGroupPermissionService.getPermissionSet(
+                getCurrentUser(), this, Collections.<String>emptySet());
+    }
+
+    @Override
+    public ObjectPermissionSet getSharingProfilePermissions()
+            throws GuacamoleException {
+        return sharingProfilePermissionService.getPermissionSet(
+                getCurrentUser(), this, Collections.<String>emptySet());
+    }
+
+    @Override
+    public ObjectPermissionSet getActiveConnectionPermissions()
+            throws GuacamoleException {
+        return activeConnectionPermissionService.getPermissionSet(
+                getCurrentUser(), this, Collections.<String>emptySet());
+    }
+
+    @Override
+    public ObjectPermissionSet getUserPermissions()
+            throws GuacamoleException {
+        return userPermissionService.getPermissionSet(getCurrentUser(), this,
+                Collections.<String>emptySet());
+    }
+
+    @Override
+    public ObjectPermissionSet getUserGroupPermissions() throws GuacamoleException {
+        // FIXME: STUB
+        return new SimpleObjectPermissionSet();
+    }
+
+    /**
+     * Returns the identifiers of all user groups defined within the database
+     * which apply to this user, including any groups inherited through
+     * membership in yet more groups.
+     *
+     * @return
+     *     The identifiers of all user groups defined within the database which
+     *     apply to this user.
+     */
+    public Set<String> getEffectiveUserGroups() {
+        return entityService.retrieveEffectiveGroups(this,
+                Collections.<String>emptySet());
+    }
+
+    /**
+     * Returns a Permissions object which represents all permissions granted to
+     * this entity, including any permissions inherited through group
+     * membership.
+     *
+     * @return
+     *     A Permissions object which represents all permissions granted to
+     *     this entity.
+     */
+    public Permissions getEffective() {
+
+        final ModeledAuthenticatedUser authenticatedUser = getCurrentUser();
+        final Set<String> effectiveGroups;
+
+        // If this user is the currently-authenticated user, include any
+        // additional effective groups declared by the authentication system
+        if (authenticatedUser.getIdentifier().equals(getIdentifier()))
+            effectiveGroups = entityService.retrieveEffectiveGroups(this,
+                    authenticatedUser.getEffectiveUserGroups());
+
+        // Otherwise, just include effective groups from the database
+        else
+            effectiveGroups = getEffectiveUserGroups();
+
+        // Return a permissions object which describes all effective
+        // permissions, including any permissions inherited via user groups
+        return new Permissions() {
+
+            @Override
+            public ObjectPermissionSet getActiveConnectionPermissions()
+                    throws GuacamoleException {
+                return activeConnectionPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups);
+            }
+
+            @Override
+            public ObjectPermissionSet getConnectionGroupPermissions()
+                    throws GuacamoleException {
+                return connectionGroupPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups);
+            }
+
+            @Override
+            public ObjectPermissionSet getConnectionPermissions()
+                    throws GuacamoleException {
+                return connectionPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups);
+            }
+
+            @Override
+            public ObjectPermissionSet getSharingProfilePermissions()
+                    throws GuacamoleException {
+                return sharingProfilePermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups);
+            }
+
+            @Override
+            public SystemPermissionSet getSystemPermissions()
+                    throws GuacamoleException {
+                return systemPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups);
+            }
+
+            @Override
+            public ObjectPermissionSet getUserPermissions()
+                    throws GuacamoleException {
+                return userPermissionService.getPermissionSet(authenticatedUser, ModeledPermissions.this, effectiveGroups);
+            }
+
+            @Override
+            public ObjectPermissionSet getUserGroupPermissions()
+                    throws GuacamoleException {
+                // FIXME: STUB
+                return new SimpleObjectPermissionSet();
+            }
+
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/AbstractPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/AbstractPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/AbstractPermissionService.java
index 74f35fb..6e4ddfa 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/AbstractPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/AbstractPermissionService.java
@@ -20,8 +20,10 @@
 package org.apache.guacamole.auth.jdbc.permission;
 
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
-import org.apache.guacamole.auth.jdbc.user.ModeledUser;
 import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
+import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
+import org.apache.guacamole.auth.jdbc.user.ModeledUser;
 import org.apache.guacamole.net.auth.permission.ObjectPermission;
 import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
 import org.apache.guacamole.net.auth.permission.Permission;
@@ -42,16 +44,50 @@ public abstract class AbstractPermissionService<PermissionSetType extends Permis
     implements PermissionService<PermissionSetType, PermissionType> {
 
     /**
+     * Returns the ObjectPermissionSet related to the type of the given entity.
+     * If the given entity represents a user, then the ObjectPermissionSet
+     * containing user permissions is returned. If the given entity represents
+     * a user group, then the ObjectPermissionSet containing user group
+     * permissions is returned.
+     *
+     * @param user
+     *     The user to retrieve the ObjectPermissionSet from.
+     *
+     * @param targetEntity
+     *     The entity whose type dictates the ObjectPermissionSet returned.
+     *
+     * @return
+     *     The ObjectPermissionSet related to the type of the given entity.
+     *
+     * @throws GuacamoleException
+     *     If the relevant ObjectPermissionSet cannot be retrieved.
+     */
+    protected ObjectPermissionSet getRelevantPermissionSet(ModeledUser user,
+            ModeledPermissions<? extends EntityModel> targetEntity)
+            throws GuacamoleException {
+
+        if (targetEntity.isUser())
+            return user.getUserPermissions();
+
+        if (targetEntity.isUserGroup())
+            return user.getUserGroupPermissions();
+
+        // Entities should be only users or groups
+        throw new UnsupportedOperationException("Unexpected entity type.");
+        
+    }
+
+    /**
      * Determines whether the given user can read the permissions currently
-     * granted to the given target user. If the reading user and the target
-     * user are not the same, then explicit READ or SYSTEM_ADMINISTER access is
-     * required. Permission inheritance via user groups is taken into account.
+     * granted to the given target entity. If the reading user and the target
+     * entity are not the same, then explicit READ or SYSTEM_ADMINISTER access
+     * is required. Permission inheritance via user groups is taken into account.
      *
      * @param user
      *     The user attempting to read permissions.
      *
-     * @param targetUser
-     *     The user whose permissions are being read.
+     * @param targetEntity
+     *     The entity whose permissions are being read.
      *
      * @return
      *     true if permission is granted, false otherwise.
@@ -61,19 +97,20 @@ public abstract class AbstractPermissionService<PermissionSetType extends Permis
      *     permission is denied to read the current user's permissions.
      */
     protected boolean canReadPermissions(ModeledAuthenticatedUser user,
-            ModeledUser targetUser) throws GuacamoleException {
+            ModeledPermissions<? extends EntityModel> targetEntity)
+            throws GuacamoleException {
 
         // A user can always read their own permissions
-        if (user.getUser().getIdentifier().equals(targetUser.getIdentifier()))
+        if (targetEntity.isUser() && user.getUser().getIdentifier().equals(targetEntity.getIdentifier()))
             return true;
         
         // A system adminstrator can do anything
         if (user.getUser().isAdministrator())
             return true;
 
-        // Can read permissions on target user if explicit READ is granted
-        ObjectPermissionSet userPermissionSet = user.getUser().getEffectivePermissions().getUserPermissions();
-        return userPermissionSet.hasPermission(ObjectPermission.Type.READ, targetUser.getIdentifier());
+        // Can read permissions on target entity if explicit READ is granted
+        ObjectPermissionSet permissionSet = getRelevantPermissionSet(user.getUser(), targetEntity);
+        return permissionSet.hasPermission(ObjectPermission.Type.READ, targetEntity.getIdentifier());
 
     }
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java
index afabbc7..d0f1f0b 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java
@@ -24,7 +24,8 @@ import com.google.inject.Provider;
 import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
 import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.auth.jdbc.user.ModeledUser;
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
+import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
 
 /**
  * Service which provides convenience methods for creating, retrieving, and
@@ -52,12 +53,12 @@ public class ConnectionGroupPermissionService extends ModeledObjectPermissionSer
 
     @Override
     public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, Set<String> effectiveGroups)
-            throws GuacamoleException {
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            Set<String> effectiveGroups) throws GuacamoleException {
 
-        // Create permission set for requested user
+        // Create permission set for requested entity
         ObjectPermissionSet permissionSet = connectionGroupPermissionSetProvider.get();
-        permissionSet.init(user, targetUser, effectiveGroups);
+        permissionSet.init(user, targetEntity, effectiveGroups);
 
         return permissionSet;
         

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java
index 0cc69df..1dc70ad 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java
@@ -24,7 +24,8 @@ import com.google.inject.Provider;
 import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
 import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.auth.jdbc.user.ModeledUser;
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
+import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
 
 /**
  * Service which provides convenience methods for creating, retrieving, and
@@ -52,12 +53,12 @@ public class ConnectionPermissionService extends ModeledObjectPermissionService
 
     @Override
     public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, Set<String> effectiveGroups)
-            throws GuacamoleException {
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            Set<String> effectiveGroups) throws GuacamoleException {
 
-        // Create permission set for requested user
+        // Create permission set for requested entity
         ObjectPermissionSet permissionSet = connectionPermissionSetProvider.get();
-        permissionSet.init(user, targetUser, effectiveGroups);
+        permissionSet.init(user, targetEntity, effectiveGroups);
 
         return permissionSet;
         

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
index f1105ed..d9bb6bc 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
@@ -24,9 +24,10 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
-import org.apache.guacamole.auth.jdbc.user.ModeledUser;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.GuacamoleSecurityException;
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
+import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
 import org.apache.guacamole.net.auth.permission.ObjectPermission;
 import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
 
@@ -48,13 +49,14 @@ public abstract class ModeledObjectPermissionService
     }
 
     @Override
-    protected ObjectPermissionModel getModelInstance(ModeledUser targetUser,
+    protected ObjectPermissionModel getModelInstance(
+            ModeledPermissions<? extends EntityModel> targetEntity,
             ObjectPermission permission) {
 
         ObjectPermissionModel model = new ObjectPermissionModel();
 
-        // Populate model object with data from user and permission
-        model.setEntityID(targetUser.getModel().getEntityID());
+        // Populate model object with data from entity and permission
+        model.setEntityID(targetEntity.getModel().getEntityID());
         model.setType(permission.getType());
         model.setObjectIdentifier(permission.getObjectIdentifier());
 
@@ -64,31 +66,32 @@ public abstract class ModeledObjectPermissionService
 
     /**
      * Determines whether the current user has permission to update the given
-     * target user, adding or removing the given permissions. Such permission
+     * target entity, adding or removing the given permissions. Such permission
      * depends on whether the current user is a system administrator, whether
-     * they have explicit UPDATE permission on the target user, and whether
+     * they have explicit UPDATE permission on the target entity, and whether
      * they have explicit ADMINISTER permission on all affected objects.
      * Permission inheritance via user groups is taken into account.
      *
      * @param user
      *     The user who is changing permissions.
      *
-     * @param targetUser
-     *     The user whose permissions are being changed.
+     * @param targetEntity
+     *     The entity whose permissions are being changed.
      *
      * @param permissions
      *     The permissions that are being added or removed from the target
-     *     user.
+     *     entity.
      *
      * @return
-     *     true if the user has permission to change the target users
+     *     true if the user has permission to change the target entity's
      *     permissions as specified, false otherwise.
      *
      * @throws GuacamoleException
      *     If an error occurs while checking permission status, or if
      *     permission is denied to read the current user's permissions.
      */
-    protected boolean canAlterPermissions(ModeledAuthenticatedUser user, ModeledUser targetUser,
+    protected boolean canAlterPermissions(ModeledAuthenticatedUser user,
+            ModeledPermissions<? extends EntityModel> targetEntity,
             Collection<ObjectPermission> permissions)
             throws GuacamoleException {
 
@@ -96,9 +99,9 @@ public abstract class ModeledObjectPermissionService
         if (user.getUser().isAdministrator())
             return true;
         
-        // Verify user has update permission on the target user
-        ObjectPermissionSet userPermissionSet = user.getUser().getEffectivePermissions().getUserPermissions();
-        if (!userPermissionSet.hasPermission(ObjectPermission.Type.UPDATE, targetUser.getIdentifier()))
+        // Verify user has update permission on the target entity
+        ObjectPermissionSet permissionSet = getRelevantPermissionSet(user.getUser(), targetEntity);
+        if (!permissionSet.hasPermission(ObjectPermission.Type.UPDATE, targetEntity.getIdentifier()))
             return false;
 
         // Produce collection of affected identifiers
@@ -122,13 +125,14 @@ public abstract class ModeledObjectPermissionService
     }
     
     @Override
-    public void createPermissions(ModeledAuthenticatedUser user, ModeledUser targetUser,
+    public void createPermissions(ModeledAuthenticatedUser user,
+            ModeledPermissions<? extends EntityModel> targetEntity,
             Collection<ObjectPermission> permissions)
             throws GuacamoleException {
 
         // Create permissions only if user has permission to do so
-        if (canAlterPermissions(user, targetUser, permissions)) {
-            Collection<ObjectPermissionModel> models = getModelInstances(targetUser, permissions);
+        if (canAlterPermissions(user, targetEntity, permissions)) {
+            Collection<ObjectPermissionModel> models = getModelInstances(targetEntity, permissions);
             getPermissionMapper().insert(models);
             return;
         }
@@ -139,13 +143,14 @@ public abstract class ModeledObjectPermissionService
     }
 
     @Override
-    public void deletePermissions(ModeledAuthenticatedUser user, ModeledUser targetUser,
+    public void deletePermissions(ModeledAuthenticatedUser user,
+            ModeledPermissions<? extends EntityModel> targetEntity,
             Collection<ObjectPermission> permissions)
             throws GuacamoleException {
 
         // Delete permissions only if user has permission to do so
-        if (canAlterPermissions(user, targetUser, permissions)) {
-            Collection<ObjectPermissionModel> models = getModelInstances(targetUser, permissions);
+        if (canAlterPermissions(user, targetEntity, permissions)) {
+            Collection<ObjectPermissionModel> models = getModelInstances(targetEntity, permissions);
             getPermissionMapper().delete(models);
             return;
         }
@@ -157,23 +162,24 @@ public abstract class ModeledObjectPermissionService
 
     @Override
     public boolean hasPermission(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, ObjectPermission.Type type,
-            String identifier, Set<String> effectiveGroups)
-            throws GuacamoleException {
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            ObjectPermission.Type type, String identifier,
+            Set<String> effectiveGroups) throws GuacamoleException {
 
         // Retrieve permissions only if allowed
-        if (canReadPermissions(user, targetUser))
-            return getPermissionMapper().selectOne(targetUser.getModel(), type,
-                    identifier, effectiveGroups) != null;
+        if (canReadPermissions(user, targetEntity))
+            return getPermissionMapper().selectOne(targetEntity.getModel(),
+                    type, identifier, effectiveGroups) != null;
 
-        // User cannot read this user's permissions
+        // User cannot read this entity's permissions
         throw new GuacamoleSecurityException("Permission denied.");
         
     }
 
     @Override
     public Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, Collection<ObjectPermission.Type> permissions,
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            Collection<ObjectPermission.Type> permissions,
             Collection<String> identifiers, Set<String> effectiveGroups)
             throws GuacamoleException {
 
@@ -182,7 +188,7 @@ public abstract class ModeledObjectPermissionService
             return identifiers;
         
         // Retrieve permissions only if allowed
-        if (canReadPermissions(user, targetUser)) {
+        if (canReadPermissions(user, targetEntity)) {
 
             // If user is an admin, everything is accessible
             if (user.getUser().isAdministrator())
@@ -190,12 +196,12 @@ public abstract class ModeledObjectPermissionService
 
             // Otherwise, return explicitly-retrievable identifiers
             return getPermissionMapper().selectAccessibleIdentifiers(
-                    targetUser.getModel(), permissions, identifiers,
+                    targetEntity.getModel(), permissions, identifiers,
                     effectiveGroups);
             
         }
 
-        // User cannot read this user's permissions
+        // User cannot read this entity's permissions
         throw new GuacamoleSecurityException("Permission denied.");
 
     }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java
index dadaea6..a102f34 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java
@@ -24,9 +24,10 @@ import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
-import org.apache.guacamole.auth.jdbc.user.ModeledUser;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.GuacamoleSecurityException;
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
+import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
 import org.apache.guacamole.net.auth.permission.Permission;
 import org.apache.guacamole.net.auth.permission.PermissionSet;
 
@@ -97,42 +98,44 @@ public abstract class ModeledPermissionService<PermissionSetType extends Permiss
 
     /**
      * Returns an instance of a model object which is based on the given
-     * permission and target user.
+     * permission and target entity.
      *
-     * @param targetUser
-     *     The user to whom this permission is granted.
+     * @param targetEntity
+     *     The entity to whom this permission is granted.
      *
      * @param permission
      *     The permission to use to produce the returned model object.
      *
      * @return
      *     A model object which is based on the given permission and target
-     *     user.
+     *     entity.
      */
-    protected abstract ModelType getModelInstance(ModeledUser targetUser,
+    protected abstract ModelType getModelInstance(
+            ModeledPermissions<? extends EntityModel> targetEntity,
             PermissionType permission);
 
     /**
      * Returns a collection of model objects which are based on the given
-     * permissions and target user.
+     * permissions and target entity.
      *
-     * @param targetUser
-     *     The user to whom this permission is granted.
+     * @param targetEntity
+     *     The entity to whom this permission is granted.
      *
      * @param permissions
      *     The permissions to use to produce the returned model objects.
      *
      * @return
      *     A collection of model objects which are based on the given
-     *     permissions and target user.
+     *     permissions and target entity.
      */
-    protected Collection<ModelType> getModelInstances(ModeledUser targetUser,
+    protected Collection<ModelType> getModelInstances(
+            ModeledPermissions<? extends EntityModel> targetEntity,
             Collection<PermissionType> permissions) {
 
         // Create new collection of models by manually converting each permission
         Collection<ModelType> models = new ArrayList<ModelType>(permissions.size());
         for (PermissionType permission : permissions)
-            models.add(getModelInstance(targetUser, permission));
+            models.add(getModelInstance(targetEntity, permission));
 
         return models;
 
@@ -140,14 +143,14 @@ public abstract class ModeledPermissionService<PermissionSetType extends Permiss
 
     @Override
     public Set<PermissionType> retrievePermissions(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, Set<String> effectiveGroups)
-            throws GuacamoleException {
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            Set<String> effectiveGroups) throws GuacamoleException {
 
         // Retrieve permissions only if allowed
-        if (canReadPermissions(user, targetUser))
-            return getPermissionInstances(getPermissionMapper().select(targetUser.getModel(), effectiveGroups));
+        if (canReadPermissions(user, targetEntity))
+            return getPermissionInstances(getPermissionMapper().select(targetEntity.getModel(), effectiveGroups));
 
-        // User cannot read this user's permissions
+        // User cannot read this entity's permissions
         throw new GuacamoleSecurityException("Permission denied.");
 
     }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java
index 3f39881..a841c96 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java
@@ -22,8 +22,9 @@ package org.apache.guacamole.auth.jdbc.permission;
 import java.util.Collection;
 import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
-import org.apache.guacamole.auth.jdbc.user.ModeledUser;
 import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
+import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
 import org.apache.guacamole.net.auth.permission.ObjectPermission;
 import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
 
@@ -37,13 +38,13 @@ public interface ObjectPermissionService
 
     /**
      * Returns whether the permission of the given type and associated with the
-     * given object has been granted to the given user.
+     * given object has been granted to the given entity.
      *
      * @param user
      *     The user retrieving the permission.
      *
-     * @param targetUser
-     *     The user associated with the permission to be retrieved.
+     * @param targetEntity
+     *     The entity associated with the permission to be retrieved.
      *
      * @param type
      *     The type of permission to retrieve.
@@ -53,30 +54,31 @@ public interface ObjectPermissionService
      *
      * @param effectiveGroups
      *     The identifiers of all groups that should be taken into account
-     *     when determining the permissions effectively granted to the user. If
-     *     no groups are given, only permissions directly granted to the user
-     *     will be used.
+     *     when determining the permissions effectively granted to the entity.
+     *     If no groups are given, only permissions directly granted to the
+     *     entity will be used.
      *
      * @return
      *     true if permission of the given type and associated with the given
-     *     object has been granted to the given user, false otherwise.
+     *     object has been granted to the given entity, false otherwise.
      *
      * @throws GuacamoleException
      *     If an error occurs while retrieving the requested permission.
      */
     boolean hasPermission(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, ObjectPermission.Type type,
-            String identifier, Set<String> effectiveGroups) throws GuacamoleException;
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            ObjectPermission.Type type, String identifier,
+            Set<String> effectiveGroups) throws GuacamoleException;
 
     /**
-     * Retrieves the subset of the given identifiers for which the given user
+     * Retrieves the subset of the given identifiers for which the given entity
      * has at least one of the given permissions.
      *
      * @param user
      *     The user checking the permissions.
      *
-     * @param targetUser
-     *     The user to check permissions of.
+     * @param targetEntity
+     *     The entity to check permissions of.
      *
      * @param permissions
      *     The permissions to check. An identifier will be included in the
@@ -89,9 +91,9 @@ public interface ObjectPermissionService
      *
      * @param effectiveGroups
      *     The identifiers of all groups that should be taken into account
-     *     when determining the permissions effectively granted to the user. If
-     *     no groups are given, only permissions directly granted to the user
-     *     will be used.
+     *     when determining the permissions effectively granted to the entity.
+     *     If no groups are given, only permissions directly granted to the
+     *     entity will be used.
      *
      * @return
      *     A collection containing the subset of identifiers for which at least
@@ -101,7 +103,8 @@ public interface ObjectPermissionService
      *     If an error occurs while retrieving permissions.
      */
     Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, Collection<ObjectPermission.Type> permissions,
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            Collection<ObjectPermission.Type> permissions,
             Collection<String> identifiers, Set<String> effectiveGroups)
             throws GuacamoleException;
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java
index c15b1af..d179c68 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java
@@ -19,29 +19,34 @@
 
 package org.apache.guacamole.auth.jdbc.permission;
 
-import org.apache.guacamole.auth.jdbc.user.ModeledUser;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
 import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
+import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
 import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
 import org.apache.guacamole.net.auth.permission.ObjectPermission;
 
 /**
  * A database implementation of ObjectPermissionSet which uses an injected
  * service to query and manipulate the object-level permissions associated with
- * a particular user.
+ * a particular entity.
  */
 public abstract class ObjectPermissionSet extends RestrictedObject
     implements org.apache.guacamole.net.auth.permission.ObjectPermissionSet {
 
     /**
-     * The user associated with this permission set. Each of the permissions in
-     * this permission set is granted to this user.
+     * The entity associated with this permission set. Each of the permissions
+     * in this permission set is granted to this entity.
      */
-    private ModeledUser user;
+    private ModeledPermissions<? extends EntityModel> entity;
 
+    /**
+     * The identifiers of all groups that should be taken into account
+     * when determining the permissions effectively granted to the entity.
+     */
     private Set<String> effectiveGroups;
 
     /**
@@ -53,26 +58,27 @@ public abstract class ObjectPermissionSet extends RestrictedObject
     }
 
     /**
-     * Initializes this permission set with the current user and the user
+     * Initializes this permission set with the current user and the entity
      * to whom the permissions in this set are granted.
      *
      * @param currentUser
      *     The user who queried this permission set, and whose permissions
      *     dictate the access level of all operations performed on this set.
      *
-     * @param user
-     *     The user to whom the permissions in this set are granted.
+     * @param entity
+     *     The entity to whom the permissions in this set are granted.
      *
      * @param effectiveGroups
      *     The identifiers of all groups that should be taken into account
-     *     when determining the permissions effectively granted to the user. If
-     *     no groups are given, only permissions directly granted to the user
-     *     will be used.
+     *     when determining the permissions effectively granted to the entity.
+     *     If no groups are given, only permissions directly granted to the
+     *     entity will be used.
      */
-    public void init(ModeledAuthenticatedUser currentUser, ModeledUser user,
+    public void init(ModeledAuthenticatedUser currentUser,
+            ModeledPermissions<? extends EntityModel> entity,
             Set<String> effectiveGroups) {
         super.init(currentUser);
-        this.user = user;
+        this.entity = entity;
         this.effectiveGroups = effectiveGroups;
     }
 
@@ -88,13 +94,13 @@ public abstract class ObjectPermissionSet extends RestrictedObject
 
     @Override
     public Set<ObjectPermission> getPermissions() throws GuacamoleException {
-        return getObjectPermissionService().retrievePermissions(getCurrentUser(), user, effectiveGroups);
+        return getObjectPermissionService().retrievePermissions(getCurrentUser(), entity, effectiveGroups);
     }
 
     @Override
     public boolean hasPermission(ObjectPermission.Type permission,
             String identifier) throws GuacamoleException {
-        return getObjectPermissionService().hasPermission(getCurrentUser(), user, permission, identifier, effectiveGroups);
+        return getObjectPermissionService().hasPermission(getCurrentUser(), entity, permission, identifier, effectiveGroups);
     }
 
     @Override
@@ -112,19 +118,19 @@ public abstract class ObjectPermissionSet extends RestrictedObject
     @Override
     public Collection<String> getAccessibleObjects(Collection<ObjectPermission.Type> permissions,
             Collection<String> identifiers) throws GuacamoleException {
-        return getObjectPermissionService().retrieveAccessibleIdentifiers(getCurrentUser(), user, permissions, identifiers, effectiveGroups);
+        return getObjectPermissionService().retrieveAccessibleIdentifiers(getCurrentUser(), entity, permissions, identifiers, effectiveGroups);
     }
 
     @Override
     public void addPermissions(Set<ObjectPermission> permissions)
             throws GuacamoleException {
-        getObjectPermissionService().createPermissions(getCurrentUser(), user, permissions);
+        getObjectPermissionService().createPermissions(getCurrentUser(), entity, permissions);
     }
 
     @Override
     public void removePermissions(Set<ObjectPermission> permissions)
             throws GuacamoleException {
-        getObjectPermissionService().deletePermissions(getCurrentUser(), user, permissions);
+        getObjectPermissionService().deletePermissions(getCurrentUser(), entity, permissions);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java
index 3caa587..5d88887 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java
@@ -22,8 +22,9 @@ package org.apache.guacamole.auth.jdbc.permission;
 import java.util.Collection;
 import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
-import org.apache.guacamole.auth.jdbc.user.ModeledUser;
 import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
+import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
 import org.apache.guacamole.net.auth.permission.Permission;
 import org.apache.guacamole.net.auth.permission.PermissionSet;
 
@@ -44,59 +45,60 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
 
     /**
      * Returns a permission set that can be used to retrieve and manipulate the
-     * permissions of the given user.
+     * permissions of the given entity.
      *
      * @param user
      *     The user who will be retrieving or manipulating permissions through
      *     the returned permission set.
      *
-     * @param targetUser
-     *     The user to whom the permissions in the returned permission set are
+     * @param targetEntity
+     *     The entity to whom the permissions in the returned permission set are
      *     granted.
      *
      * @param effectiveGroups
      *     The identifiers of all groups that should be taken into account
-     *     when determining the permissions effectively granted to the user. If
-     *     no groups are given, only permissions directly granted to the user
-     *     will be used.
+     *     when determining the permissions effectively granted to the entity.
+     *     If no groups are given, only permissions directly granted to the
+     *     entity will be used.
      *
      * @return
      *     A permission set that contains all permissions associated with the
-     *     given user, and can be used to manipulate that user's permissions.
+     *     given entity, and can be used to manipulate that entity's
+     *     permissions.
      *
      * @throws GuacamoleException
      *     If an error occurs while retrieving the permissions of the given
-     *     user, or if permission to retrieve the permissions of the given
-     *     user is denied.
+     *     entity, or if permission to retrieve the permissions of the given
+     *     entity is denied.
      */
     PermissionSetType getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, Set<String> effectiveGroups)
-            throws GuacamoleException;
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            Set<String> effectiveGroups) throws GuacamoleException;
 
     /**
-     * Retrieves all permissions associated with the given user.
+     * Retrieves all permissions associated with the given entity.
      *
      * @param user
      *     The user retrieving the permissions.
      *
-     * @param targetUser
-     *     The user associated with the permissions to be retrieved.
+     * @param targetEntity
+     *     The entity associated with the permissions to be retrieved.
      *
      * @param effectiveGroups
      *     The identifiers of all groups that should be taken into account
-     *     when determining the permissions effectively granted to the user. If
-     *     no groups are given, only permissions directly granted to the user
-     *     will be used.
+     *     when determining the permissions effectively granted to the entity.
+     *     If no groups are given, only permissions directly granted to the
+     *     entity will be used.
      *
      * @return
-     *     The permissions associated with the given user.
+     *     The permissions associated with the given entity.
      *
      * @throws GuacamoleException
      *     If an error occurs while retrieving the requested permissions.
      */
     Set<PermissionType> retrievePermissions(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, Set<String> effectiveGroups)
-            throws GuacamoleException;
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            Set<String> effectiveGroups) throws GuacamoleException;
 
     /**
      * Creates the given permissions within the database. If any permissions
@@ -105,8 +107,8 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
      * @param user
      *     The user creating the permissions.
      *
-     * @param targetUser
-     *     The user associated with the permissions to be created.
+     * @param targetEntity
+     *     The entity associated with the permissions to be created.
      *
      * @param permissions 
      *     The permissions to create.
@@ -115,8 +117,10 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
      *     If the user lacks permission to create the permissions, or an error
      *     occurs while creating the permissions.
      */
-    void createPermissions(ModeledAuthenticatedUser user, ModeledUser targetUser,
-            Collection<PermissionType> permissions) throws GuacamoleException;
+    void createPermissions(ModeledAuthenticatedUser user,
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            Collection<PermissionType> permissions)
+            throws GuacamoleException;
 
     /**
      * Deletes the given permissions. If any permissions do not exist, they
@@ -125,17 +129,19 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
      * @param user
      *     The user deleting the permissions.
      *
-     * @param targetUser
-     *     The user associated with the permissions to be deleted.
+     * @param targetEntity
+     *     The entity associated with the permissions to be deleted.
      *
      * @param permissions
      *     The permissions to delete.
      *
      * @throws GuacamoleException
-     *     If the user lacks permission to delete the permissions, or an error
+     *     If the entity lacks permission to delete the permissions, or an error
      *     occurs while deleting the permissions.
      */
-    void deletePermissions(ModeledAuthenticatedUser user, ModeledUser targetUser,
-            Collection<PermissionType> permissions) throws GuacamoleException;
+    void deletePermissions(ModeledAuthenticatedUser user,
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            Collection<PermissionType> permissions)
+            throws GuacamoleException;
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java
index 3018b29..c30ff73 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java
@@ -24,7 +24,8 @@ import com.google.inject.Provider;
 import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
 import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.auth.jdbc.user.ModeledUser;
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
+import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
 
 /**
  * Service which provides convenience methods for creating, retrieving, and
@@ -52,12 +53,12 @@ public class SharingProfilePermissionService extends ModeledObjectPermissionServ
 
     @Override
     public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, Set<String> effectiveGroups)
-            throws GuacamoleException {
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            Set<String> effectiveGroups) throws GuacamoleException {
 
-        // Create permission set for requested user
+        // Create permission set for requested entity
         ObjectPermissionSet permissionSet = sharingProfilePermissionSetProvider.get();
-        permissionSet.init(user, targetUser, effectiveGroups);
+        permissionSet.init(user, targetEntity, effectiveGroups);
 
         return permissionSet;
         

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
index b534ad3..c94a260 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
@@ -24,10 +24,11 @@ import com.google.inject.Provider;
 import java.util.Collection;
 import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
-import org.apache.guacamole.auth.jdbc.user.ModeledUser;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.GuacamoleSecurityException;
 import org.apache.guacamole.GuacamoleUnsupportedException;
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
+import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
 import org.apache.guacamole.net.auth.permission.SystemPermission;
 
 /**
@@ -61,13 +62,14 @@ public class SystemPermissionService
     }
 
     @Override
-    protected SystemPermissionModel getModelInstance(final ModeledUser targetUser,
+    protected SystemPermissionModel getModelInstance(
+            final ModeledPermissions<? extends EntityModel> targetEntity,
             final SystemPermission permission) {
 
         SystemPermissionModel model = new SystemPermissionModel();
 
         // Populate model object with data from user and permission
-        model.setEntityID(targetUser.getModel().getEntityID());
+        model.setEntityID(targetEntity.getModel().getEntityID());
         model.setType(permission.getType());
 
         return model;
@@ -76,23 +78,25 @@ public class SystemPermissionService
 
     @Override
     public SystemPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, Set<String> effectiveGroups) throws GuacamoleException {
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            Set<String> effectiveGroups) throws GuacamoleException {
 
         // Create permission set for requested user
         SystemPermissionSet permissionSet = systemPermissionSetProvider.get();
-        permissionSet.init(user, targetUser, effectiveGroups);
+        permissionSet.init(user, targetEntity, effectiveGroups);
 
         return permissionSet;
         
     }
     
     @Override
-    public void createPermissions(ModeledAuthenticatedUser user, ModeledUser targetUser,
+    public void createPermissions(ModeledAuthenticatedUser user,
+            ModeledPermissions<? extends EntityModel> targetEntity,
             Collection<SystemPermission> permissions) throws GuacamoleException {
 
         // Only an admin can create system permissions
         if (user.getUser().isAdministrator()) {
-            Collection<SystemPermissionModel> models = getModelInstances(targetUser, permissions);
+            Collection<SystemPermissionModel> models = getModelInstances(targetEntity, permissions);
             systemPermissionMapper.insert(models);
             return;
         }
@@ -103,17 +107,18 @@ public class SystemPermissionService
     }
 
     @Override
-    public void deletePermissions(ModeledAuthenticatedUser user, ModeledUser targetUser,
+    public void deletePermissions(ModeledAuthenticatedUser user,
+            ModeledPermissions<? extends EntityModel> targetEntity,
             Collection<SystemPermission> permissions) throws GuacamoleException {
 
         // Only an admin can delete system permissions
         if (user.getUser().isAdministrator()) {
 
             // Do not allow users to remove their own admin powers
-            if (user.getUser().getIdentifier().equals(targetUser.getIdentifier()))
+            if (user.getUser().getIdentifier().equals(targetEntity.getIdentifier()))
                 throw new GuacamoleUnsupportedException("Removing your own administrative permissions is not allowed.");
             
-            Collection<SystemPermissionModel> models = getModelInstances(targetUser, permissions);
+            Collection<SystemPermissionModel> models = getModelInstances(targetEntity, permissions);
             systemPermissionMapper.delete(models);
             return;
         }
@@ -125,14 +130,14 @@ public class SystemPermissionService
 
     /**
      * Retrieves whether the permission of the given type has been granted to
-     * the given user. Permission inheritance through group membership is taken
-     * into account.
+     * the given entity. Permission inheritance through group membership is
+     * taken into account.
      *
      * @param user
      *     The user retrieving the permission.
      *
-     * @param targetUser
-     *     The user associated with the permission to be retrieved.
+     * @param targetEntity
+     *     The entity associated with the permission to be retrieved.
      * 
      * @param type
      *     The type of permission to retrieve.
@@ -151,12 +156,13 @@ public class SystemPermissionService
      *     If an error occurs while retrieving the requested permission.
      */
     public boolean hasPermission(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, SystemPermission.Type type,
-            Set<String> effectiveGroups) throws GuacamoleException {
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            SystemPermission.Type type, Set<String> effectiveGroups)
+            throws GuacamoleException {
 
         // Retrieve permissions only if allowed
-        if (canReadPermissions(user, targetUser))
-            return getPermissionMapper().selectOne(targetUser.getModel(), type, effectiveGroups) != null;
+        if (canReadPermissions(user, targetEntity))
+            return getPermissionMapper().selectOne(targetEntity.getModel(), type, effectiveGroups) != null;
 
         // User cannot read this user's permissions
         throw new GuacamoleSecurityException("Permission denied.");

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java
index dd88879..1948fac 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java
@@ -19,29 +19,34 @@
 
 package org.apache.guacamole.auth.jdbc.permission;
 
-import org.apache.guacamole.auth.jdbc.user.ModeledUser;
 import com.google.inject.Inject;
 import java.util.Collections;
 import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
 import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
+import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
 import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
 import org.apache.guacamole.net.auth.permission.SystemPermission;
 
 /**
  * A database implementation of SystemPermissionSet which uses an injected
  * service to query and manipulate the system permissions associated with a
- * particular user.
+ * particular entity.
  */
 public class SystemPermissionSet extends RestrictedObject
     implements org.apache.guacamole.net.auth.permission.SystemPermissionSet {
 
     /**
-     * The user associated with this permission set. Each of the permissions in
-     * this permission set is granted to this user.
+     * The entity associated with this permission set. Each of the permissions
+     * in this permission set is granted to this entity.
      */
-    private ModeledUser user;
+    private ModeledPermissions<? extends EntityModel> entity;
 
+    /**
+     * The identifiers of all groups that should be taken into account when
+     * determining the permissions effectively granted to the entity.
+     */
     private Set<String> effectiveGroups;
 
     /**
@@ -59,38 +64,39 @@ public class SystemPermissionSet extends RestrictedObject
     }
 
     /**
-     * Initializes this permission set with the current user and the user
+     * Initializes this permission set with the current user and the entity
      * to whom the permissions in this set are granted.
      *
      * @param currentUser
      *     The user who queried this permission set, and whose permissions
      *     dictate the access level of all operations performed on this set.
      *
-     * @param user
-     *     The user to whom the permissions in this set are granted.
+     * @param entity
+     *     The entity to whom the permissions in this set are granted.
      *
      * @param effectiveGroups
      *     The identifiers of all groups that should be taken into account
-     *     when determining the permissions effectively granted to the user. If
-     *     no groups are given, only permissions directly granted to the user
-     *     will be used.
+     *     when determining the permissions effectively granted to the entity.
+     *     If no groups are given, only permissions directly granted to the
+     *     entity will be used.
      */
-    public void init(ModeledAuthenticatedUser currentUser, ModeledUser user,
+    public void init(ModeledAuthenticatedUser currentUser,
+            ModeledPermissions<? extends EntityModel> entity,
             Set<String> effectiveGroups) {
         super.init(currentUser);
-        this.user = user;
+        this.entity = entity;
         this.effectiveGroups = effectiveGroups;
     }
 
     @Override
     public Set<SystemPermission> getPermissions() throws GuacamoleException {
-        return systemPermissionService.retrievePermissions(getCurrentUser(), user, effectiveGroups);
+        return systemPermissionService.retrievePermissions(getCurrentUser(), entity, effectiveGroups);
     }
 
     @Override
     public boolean hasPermission(SystemPermission.Type permission)
             throws GuacamoleException {
-        return systemPermissionService.hasPermission(getCurrentUser(), user, permission, effectiveGroups);
+        return systemPermissionService.hasPermission(getCurrentUser(), entity, permission, effectiveGroups);
     }
 
     @Override
@@ -108,13 +114,13 @@ public class SystemPermissionSet extends RestrictedObject
     @Override
     public void addPermissions(Set<SystemPermission> permissions)
             throws GuacamoleException {
-        systemPermissionService.createPermissions(getCurrentUser(), user, permissions);
+        systemPermissionService.createPermissions(getCurrentUser(), entity, permissions);
     }
 
     @Override
     public void removePermissions(Set<SystemPermission> permissions)
             throws GuacamoleException {
-        systemPermissionService.deletePermissions(getCurrentUser(), user, permissions);
+        systemPermissionService.deletePermissions(getCurrentUser(), entity, permissions);
     }
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/69f58c8c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java
index fabbf72..ed8689a 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java
@@ -24,7 +24,8 @@ import com.google.inject.Provider;
 import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
 import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.auth.jdbc.user.ModeledUser;
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
+import org.apache.guacamole.auth.jdbc.base.ModeledPermissions;
 
 /**
  * Service which provides convenience methods for creating, retrieving, and
@@ -52,12 +53,12 @@ public class UserPermissionService extends ModeledObjectPermissionService {
 
     @Override
     public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, Set<String> effectiveGroups)
-            throws GuacamoleException {
+            ModeledPermissions<? extends EntityModel> targetEntity,
+            Set<String> effectiveGroups) throws GuacamoleException {
 
-        // Create permission set for requested user
+        // Create permission set for requested entity
         ObjectPermissionSet permissionSet = userPermissionSetProvider.get();
-        permissionSet.init(user, targetUser, effectiveGroups);
+        permissionSet.init(user, targetEntity, effectiveGroups);
 
         return permissionSet;
         


[11/38] guacamole-client git commit: GUACAMOLE-220: Refactor user-related model objects and services to leverage the base "entity" model.

Posted by vn...@apache.org.
GUACAMOLE-220: Refactor user-related model objects and services to leverage the base "entity" model.

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

Branch: refs/heads/master
Commit: d95e05961275a773aa689adac6dae7d204426201
Parents: e72f88f
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Apr 3 11:17:31 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:51 2018 -0700

----------------------------------------------------------------------
 .../guacamole/auth/jdbc/base/EntityModel.java   | 113 +++++++++++++++++++
 .../guacamole/auth/jdbc/base/EntityType.java    |  38 +++++++
 .../base/ModeledDirectoryObjectService.java     |   3 +-
 .../ModeledObjectPermissionService.java         |   3 +-
 .../jdbc/permission/ObjectPermissionMapper.java |  20 ++--
 .../auth/jdbc/permission/PermissionMapper.java  |  13 ++-
 .../auth/jdbc/permission/PermissionModel.java   |  50 +++-----
 .../jdbc/permission/SystemPermissionMapper.java |  12 +-
 .../permission/SystemPermissionService.java     |   3 +-
 .../guacamole/auth/jdbc/user/UserModel.java     |   6 +-
 .../guacamole/auth/jdbc/user/UserService.java   |   5 +-
 11 files changed, 195 insertions(+), 71 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/d95e0596/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityModel.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityModel.java
new file mode 100644
index 0000000..c42db16
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityModel.java
@@ -0,0 +1,113 @@
+/*
+ * 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.base;
+
+/**
+ * Base representation of a Guacamole object that can be granted permissions
+ * (an "entity"), such as a user or user group, as represented in the database.
+ * Each entity has three base properties:
+ *
+ *   1. The "entityID", which points to the common entry in the
+ *      guacamole_entity table and is common to any type of entity.
+ *
+ *   2. The "objectID", which points to the type-specific entry for the object
+ *      in question (ie: an entry in guacamole_user or guacamole_user_group).
+ *
+ *   3. The "identifier", which contains the unique "name" value defined for
+ *      the entity within the guacamole_entity table.
+ */
+public abstract class EntityModel extends ObjectModel {
+
+    /**
+     * The ID of the entity entry which corresponds to this object in the
+     * database, if any. Note that this is distinct from the objectID,
+     * inherited from ObjectModel, which is specific to the actual type of
+     * object represented by the entity.
+     */
+    private Integer entityID;
+
+    /**
+     * The type of object represented by the entity (user or user group).
+     */
+    private EntityType type;
+
+    /**
+     * Creates a new, empty entity.
+     */
+    public EntityModel() {
+    }
+
+    /**
+     * Creates a new entity of the given type which is otherwise empty.
+     *
+     * @param type
+     *     The type to assign to the new entity.
+     */
+    public EntityModel(EntityType type) {
+        this.type = type;
+    }
+
+    /**
+     * Returns the ID of the entity entry which corresponds to this object in
+     * the database, if it exists. Note that this is distinct from the objectID,
+     * inherited from ObjectModel, which is specific to the actual type of
+     * object represented by the entity.
+     *
+     * @return
+     *     The ID of this entity in the database, or null if this entity was
+     *     not retrieved from the database.
+     */
+    public Integer getEntityID() {
+        return entityID;
+    }
+
+    /**
+     * Sets the ID of this entity to the given value.
+     *
+     * @param entityID
+     *     The ID to assign to this entity.
+     */
+    public void setEntityID(Integer entityID) {
+        this.entityID = entityID;
+    }
+
+    /**
+     * Returns the type of object represented by the entity. Each entity may be
+     * either a user or a user group.
+     *
+     * @return
+     *     The type of object represented by the entity.
+     */
+    public EntityType getEntityType() {
+        return type;
+    }
+
+    /**
+     * Sets the type of object represented by the entity. Each entity may be
+     * either a user or a user group.
+     *
+     * @param type
+     *     The type of object represented by the entity.
+     */
+    public void setEntityType(EntityType type) {
+        this.type = type;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/d95e0596/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityType.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityType.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityType.java
new file mode 100644
index 0000000..9b1f1ed
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityType.java
@@ -0,0 +1,38 @@
+/*
+ * 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.base;
+
+/**
+ * The type of object represented by an entity. Each entity may represent
+ * either a user or a user group.
+ */
+public enum EntityType {
+
+    /**
+     * An individual user.
+     */
+    USER,
+
+    /**
+     * A group of users and/or other groups.
+     */
+    USER_GROUP
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/d95e0596/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java
index 21508c4..3e3e707 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java
@@ -432,8 +432,7 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
 
             // Create model which grants this permission to the current user
             ObjectPermissionModel permissionModel = new ObjectPermissionModel();
-            permissionModel.setUserID(userModel.getObjectID());
-            permissionModel.setUsername(userModel.getIdentifier());
+            permissionModel.setEntityID(userModel.getEntityID());
             permissionModel.setType(permission);
             permissionModel.setObjectIdentifier(model.getIdentifier());
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/d95e0596/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
index a4f1f3f..9197217 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
@@ -53,8 +53,7 @@ public abstract class ModeledObjectPermissionService
         ObjectPermissionModel model = new ObjectPermissionModel();
 
         // Populate model object with data from user and permission
-        model.setUserID(targetUser.getModel().getObjectID());
-        model.setUsername(targetUser.getModel().getIdentifier());
+        model.setEntityID(targetUser.getModel().getEntityID());
         model.setType(permission.getType());
         model.setObjectIdentifier(permission.getObjectIdentifier());
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/d95e0596/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java
index ff8369a..f744fbf 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java
@@ -20,8 +20,8 @@
 package org.apache.guacamole.auth.jdbc.permission;
 
 import java.util.Collection;
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
 import org.apache.ibatis.annotations.Param;
-import org.apache.guacamole.auth.jdbc.user.UserModel;
 import org.apache.guacamole.net.auth.permission.ObjectPermission;
 
 /**
@@ -31,11 +31,11 @@ public interface ObjectPermissionMapper extends PermissionMapper<ObjectPermissio
 
     /**
      * Retrieve the permission of the given type associated with the given
-     * user and object, if it exists. If no such permission exists, null is
+     * entity and object, if it exists. If no such permission exists, null is
      * returned.
      *
-     * @param user
-     *     The user to retrieve permissions for.
+     * @param entity
+     *     The entity to retrieve permissions for.
      * 
      * @param type
      *     The type of permission to return.
@@ -45,18 +45,18 @@ public interface ObjectPermissionMapper extends PermissionMapper<ObjectPermissio
      *
      * @return
      *     The requested permission, or null if no such permission is granted
-     *     to the given user for the given object.
+     *     to the given entity for the given object.
      */
-    ObjectPermissionModel selectOne(@Param("user") UserModel user,
+    ObjectPermissionModel selectOne(@Param("entity") EntityModel entity,
             @Param("type") ObjectPermission.Type type,
             @Param("identifier") String identifier);
 
     /**
-     * Retrieves the subset of the given identifiers for which the given user
+     * Retrieves the subset of the given identifiers for which the given entity
      * has at least one of the given permissions.
      *
-     * @param user
-     *     The user to check permissions of.
+     * @param entity
+     *     The entity to check permissions of.
      *
      * @param permissions
      *     The permissions to check. An identifier will be included in the
@@ -71,7 +71,7 @@ public interface ObjectPermissionMapper extends PermissionMapper<ObjectPermissio
      *     A collection containing the subset of identifiers for which at least
      *     one of the specified permissions is granted.
      */
-    Collection<String> selectAccessibleIdentifiers(@Param("user") UserModel user,
+    Collection<String> selectAccessibleIdentifiers(@Param("entity") EntityModel entity,
             @Param("permissions") Collection<ObjectPermission.Type> permissions,
             @Param("identifiers") Collection<String> identifiers);
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/d95e0596/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java
index d49dc30..7b476b3 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java
@@ -20,7 +20,7 @@
 package org.apache.guacamole.auth.jdbc.permission;
 
 import java.util.Collection;
-import org.apache.guacamole.auth.jdbc.user.UserModel;
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
 import org.apache.ibatis.annotations.Param;
 
 /**
@@ -32,15 +32,16 @@ import org.apache.ibatis.annotations.Param;
 public interface PermissionMapper<PermissionType> {
 
     /**
-     * Retrieves all permissions associated with the given user.
+     * Retrieves all permissions associated with the given entity (user or user
+     * group).
      *
-     * @param user
-     *     The user to retrieve permissions for.
+     * @param entity
+     *     The entity to retrieve permissions for.
      *
      * @return
-     *     All permissions associated with the given user.
+     *     All permissions associated with the given entity.
      */
-    Collection<PermissionType> select(@Param("user") UserModel user);
+    Collection<PermissionType> select(@Param("entity") EntityModel entity);
 
     /**
      * Inserts the given permissions into the database. If any permissions

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/d95e0596/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionModel.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionModel.java
index fbc3e8d..da1ec2d 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionModel.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionModel.java
@@ -21,7 +21,7 @@ package org.apache.guacamole.auth.jdbc.permission;
 
 /**
  * Generic base permission model which grants a permission of a particular type
- * to a specific user.
+ * to a specific entity (user or user group).
  *
  * @param <PermissionType>
  *     The type of permissions allowed within this model.
@@ -29,14 +29,9 @@ package org.apache.guacamole.auth.jdbc.permission;
 public abstract class PermissionModel<PermissionType> {
 
     /**
-     * The database ID of the user to whom this permission is granted.
+     * The database ID of the entity to whom this permission is granted.
      */
-    private Integer userID;
-
-    /**
-     * The username of the user to whom this permission is granted.
-     */
-    private String username;
+    private Integer entityID;
 
     /**
      * The type of action granted by this permission.
@@ -44,43 +39,24 @@ public abstract class PermissionModel<PermissionType> {
     private PermissionType type;
     
     /**
-     * Returns the database ID of the user to whom this permission is granted.
-     * 
-     * @return
-     *     The database ID of the user to whom this permission is granted.
-     */
-    public Integer getUserID() {
-        return userID;
-    }
-
-    /**
-     * Sets the database ID of the user to whom this permission is granted.
-     *
-     * @param userID
-     *     The database ID of the user to whom this permission is granted.
-     */
-    public void setUserID(Integer userID) {
-        this.userID = userID;
-    }
-
-    /**
-     * Returns the username of the user to whom this permission is granted.
+     * Returns the database ID of the entity to whom this permission is
+     * granted.
      * 
      * @return
-     *     The username of the user to whom this permission is granted.
+     *     The database ID of the entity to whom this permission is granted.
      */
-    public String getUsername() {
-        return username;
+    public Integer getEntityID() {
+        return entityID;
     }
 
     /**
-     * Sets the username of the user to whom this permission is granted.
+     * Sets the database ID of the entity to whom this permission is granted.
      *
-     * @param username
-     *     The username of the user to whom this permission is granted.
+     * @param entityID
+     *     The database ID of the entity to whom this permission is granted.
      */
-    public void setUsername(String username) {
-        this.username = username;
+    public void setEntityID(Integer entityID) {
+        this.entityID = entityID;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/d95e0596/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java
index 929d6e9..738062c 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java
@@ -19,7 +19,7 @@
 
 package org.apache.guacamole.auth.jdbc.permission;
 
-import org.apache.guacamole.auth.jdbc.user.UserModel;
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
 import org.apache.ibatis.annotations.Param;
 import org.apache.guacamole.net.auth.permission.SystemPermission;
 
@@ -30,19 +30,19 @@ public interface SystemPermissionMapper extends PermissionMapper<SystemPermissio
 
     /**
      * Retrieve the permission of the given type associated with the given
-     * user, if it exists. If no such permission exists, null is returned.
+     * entity, if it exists. If no such permission exists, null is returned.
      *
-     * @param user
-     *     The user to retrieve permissions for.
+     * @param entity
+     *     The entity to retrieve permissions for.
      * 
      * @param type
      *     The type of permission to return.
      *
      * @return
      *     The requested permission, or null if no such permission is granted
-     *     to the given user.
+     *     to the given entity.
      */
-    SystemPermissionModel selectOne(@Param("user") UserModel user,
+    SystemPermissionModel selectOne(@Param("entity") EntityModel entity,
             @Param("type") SystemPermission.Type type);
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/d95e0596/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
index db1d81e..e50a47f 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
@@ -66,8 +66,7 @@ public class SystemPermissionService
         SystemPermissionModel model = new SystemPermissionModel();
 
         // Populate model object with data from user and permission
-        model.setUserID(targetUser.getModel().getObjectID());
-        model.setUsername(targetUser.getModel().getIdentifier());
+        model.setEntityID(targetUser.getModel().getEntityID());
         model.setType(permission.getType());
 
         return model;

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/d95e0596/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java
index a6cf997..194a26d 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserModel.java
@@ -22,12 +22,13 @@ package org.apache.guacamole.auth.jdbc.user;
 import java.sql.Date;
 import java.sql.Time;
 import java.sql.Timestamp;
-import org.apache.guacamole.auth.jdbc.base.ObjectModel;
+import org.apache.guacamole.auth.jdbc.base.EntityModel;
+import org.apache.guacamole.auth.jdbc.base.EntityType;
 
 /**
  * Object representation of a Guacamole user, as represented in the database.
  */
-public class UserModel extends ObjectModel {
+public class UserModel extends EntityModel {
 
     /**
      * The SHA-256 hash of the password and salt.
@@ -124,6 +125,7 @@ public class UserModel extends ObjectModel {
      * Creates a new, empty user.
      */
     public UserModel() {
+        super(EntityType.USER);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/d95e0596/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
index 090963f..e4bb738 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
@@ -38,7 +38,6 @@ import org.apache.guacamole.auth.jdbc.base.ActivityRecordModel;
 import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
 import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
 import org.apache.guacamole.auth.jdbc.base.ModeledActivityRecord;
-import org.apache.guacamole.auth.jdbc.connection.ConnectionRecordModel;
 import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
 import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel;
 import org.apache.guacamole.auth.jdbc.permission.UserPermissionMapper;
@@ -49,7 +48,6 @@ import org.apache.guacamole.form.PasswordField;
 import org.apache.guacamole.net.auth.ActivityRecord;
 import org.apache.guacamole.net.auth.AuthenticatedUser;
 import org.apache.guacamole.net.auth.AuthenticationProvider;
-import org.apache.guacamole.net.auth.ConnectionRecord;
 import org.apache.guacamole.net.auth.User;
 import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
 import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException;
@@ -294,8 +292,7 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
         for (ObjectPermission.Type permissionType : IMPLICIT_USER_PERMISSIONS) {
             
             ObjectPermissionModel permissionModel = new ObjectPermissionModel();
-            permissionModel.setUserID(model.getObjectID());
-            permissionModel.setUsername(model.getIdentifier());
+            permissionModel.setEntityID(model.getEntityID());
             permissionModel.setType(permissionType);
             permissionModel.setObjectIdentifier(model.getIdentifier());
 


[35/38] guacamole-client git commit: GUACAMOLE-220: Remove effectively-redundant admin permission check.

Posted by vn...@apache.org.
GUACAMOLE-220: Remove effectively-redundant admin permission check.

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

Branch: refs/heads/master
Commit: f4ccf8ef626e236f39ed24b1ab28f2cc9699dee7
Parents: bb6e8bc
Author: Michael Jumper <mj...@apache.org>
Authored: Sun Sep 30 23:11:20 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Sun Sep 30 23:11:20 2018 -0700

----------------------------------------------------------------------
 .../permission/ModeledObjectPermissionService.java    | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/f4ccf8ef/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
index d9bb6bc..8c4be58 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
@@ -187,19 +187,15 @@ public abstract class ModeledObjectPermissionService
         if (identifiers.isEmpty())
             return identifiers;
         
-        // Retrieve permissions only if allowed
-        if (canReadPermissions(user, targetEntity)) {
-
-            // If user is an admin, everything is accessible
-            if (user.getUser().isAdministrator())
-                return identifiers;
+        // If user is an admin, everything is accessible
+        if (user.getUser().isAdministrator())
+            return identifiers;
 
-            // Otherwise, return explicitly-retrievable identifiers
+        // Otherwise, return explicitly-retrievable identifiers only if allowed
+        if (canReadPermissions(user, targetEntity))
             return getPermissionMapper().selectAccessibleIdentifiers(
                     targetEntity.getModel(), permissions, identifiers,
                     effectiveGroups);
-            
-        }
 
         // User cannot read this entity's permissions
         throw new GuacamoleSecurityException("Permission denied.");


[37/38] guacamole-client git commit: GUACAMOLE-220: Merge add database support for user groups.

Posted by vn...@apache.org.
GUACAMOLE-220: Merge add database support for user groups.


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

Branch: refs/heads/master
Commit: 828313541b1903cc148f8d04b8bdcd4d5006dcd4
Parents: aa7cd9d 4d51962
Author: Nick Couchman <vn...@apache.org>
Authored: Mon Oct 1 13:33:07 2018 -0400
Committer: Nick Couchman <vn...@apache.org>
Committed: Mon Oct 1 13:38:55 2018 -0400

----------------------------------------------------------------------
 .../modules/guacamole-auth-jdbc-base/pom.xml    |  10 +-
 .../jdbc/JDBCAuthenticationProviderModule.java  |  26 +
 .../guacamole/auth/jdbc/JDBCEnvironment.java    |  15 +
 .../ActiveConnectionPermissionService.java      |  51 +-
 .../guacamole/auth/jdbc/base/EntityMapper.java  |  80 +++
 .../guacamole/auth/jdbc/base/EntityModel.java   | 113 ++++
 .../guacamole/auth/jdbc/base/EntityService.java |  98 ++++
 .../guacamole/auth/jdbc/base/EntityType.java    |  38 ++
 .../ModeledChildDirectoryObjectService.java     |   7 +-
 .../jdbc/base/ModeledDirectoryObjectMapper.java |  14 +-
 .../base/ModeledDirectoryObjectService.java     |  22 +-
 .../auth/jdbc/base/ModeledPermissions.java      | 271 ++++++++++
 .../auth/jdbc/base/ObjectRelationMapper.java    | 126 +++++
 .../auth/jdbc/base/RelatedObjectSet.java        | 211 ++++++++
 .../auth/jdbc/connection/ConnectionMapper.java  |  10 +-
 .../jdbc/connection/ConnectionRecordMapper.java |   9 +-
 .../auth/jdbc/connection/ConnectionService.java |  19 +-
 .../connectiongroup/ConnectionGroupMapper.java  |  10 +-
 .../connectiongroup/ConnectionGroupService.java |  14 +-
 .../permission/AbstractPermissionService.java   |  59 +-
 .../ConnectionGroupPermissionService.java       |  11 +-
 .../permission/ConnectionPermissionService.java |  11 +-
 .../ModeledObjectPermissionService.java         |  98 ++--
 .../permission/ModeledPermissionService.java    |  44 +-
 .../jdbc/permission/ObjectPermissionMapper.java |  42 +-
 .../permission/ObjectPermissionService.java     |  49 +-
 .../jdbc/permission/ObjectPermissionSet.java    |  48 +-
 .../auth/jdbc/permission/PermissionMapper.java  |  20 +-
 .../auth/jdbc/permission/PermissionModel.java   |  50 +-
 .../auth/jdbc/permission/PermissionService.java |  67 ++-
 .../SharingProfilePermissionService.java        |  11 +-
 .../jdbc/permission/SystemPermissionMapper.java |  24 +-
 .../permission/SystemPermissionService.java     |  70 +--
 .../jdbc/permission/SystemPermissionSet.java    |  44 +-
 .../permission/UserGroupPermissionMapper.java   |  25 +
 .../permission/UserGroupPermissionService.java  |  67 +++
 .../jdbc/permission/UserGroupPermissionSet.java |  42 ++
 .../jdbc/permission/UserPermissionService.java  |  11 +-
 .../sharing/user/SharedAuthenticatedUser.java   |  11 +-
 .../sharingprofile/SharingProfileService.java   |  10 +-
 .../tunnel/AbstractGuacamoleTunnelService.java  |   4 +-
 .../jdbc/user/ModeledAuthenticatedUser.java     |   9 +-
 .../guacamole/auth/jdbc/user/ModeledUser.java   | 114 +---
 .../auth/jdbc/user/ModeledUserContext.java      |  16 +-
 .../auth/jdbc/user/RemoteAuthenticatedUser.java |  20 +-
 .../guacamole/auth/jdbc/user/UserMapper.java    |   2 +-
 .../guacamole/auth/jdbc/user/UserModel.java     |   6 +-
 .../jdbc/user/UserParentUserGroupMapper.java    |  28 +
 .../auth/jdbc/user/UserParentUserGroupSet.java  |  59 ++
 .../auth/jdbc/user/UserRecordMapper.java        |   9 +-
 .../guacamole/auth/jdbc/user/UserService.java   |  24 +-
 .../auth/jdbc/usergroup/ModeledUserGroup.java   | 206 +++++++
 .../auth/jdbc/usergroup/UserGroupDirectory.java |  82 +++
 .../auth/jdbc/usergroup/UserGroupMapper.java    |  42 ++
 .../UserGroupMemberUserGroupMapper.java         |  28 +
 .../usergroup/UserGroupMemberUserGroupSet.java  |  57 ++
 .../usergroup/UserGroupMemberUserMapper.java    |  28 +
 .../jdbc/usergroup/UserGroupMemberUserSet.java  |  57 ++
 .../auth/jdbc/usergroup/UserGroupModel.java     |  68 +++
 .../UserGroupParentUserGroupMapper.java         |  28 +
 .../usergroup/UserGroupParentUserGroupSet.java  |  58 ++
 .../auth/jdbc/usergroup/UserGroupService.java   | 183 +++++++
 .../src/main/resources/translations/en.json     |   8 +
 .../schema/001-create-schema.sql                | 196 +++++--
 .../schema/002-create-admin-user.sql            |  26 +-
 .../schema/upgrade/upgrade-pre-1.0.0.sql        | 335 ++++++++++++
 .../guacamole/auth/mysql/MySQLEnvironment.java  |  55 +-
 .../guacamole/auth/mysql/MySQLVersion.java      | 153 ++++++
 .../guacamole/auth/jdbc/base/EntityMapper.xml   | 156 ++++++
 .../auth/jdbc/connection/ConnectionMapper.xml   |  30 +-
 .../jdbc/connection/ConnectionRecordMapper.xml  |  22 +-
 .../connectiongroup/ConnectionGroupMapper.xml   |  36 +-
 .../ConnectionGroupPermissionMapper.xml         |  44 +-
 .../permission/ConnectionPermissionMapper.xml   |  44 +-
 .../SharingProfilePermissionMapper.xml          |  46 +-
 .../jdbc/permission/SystemPermissionMapper.xml  |  40 +-
 .../permission/UserGroupPermissionMapper.xml    | 149 ++++++
 .../jdbc/permission/UserPermissionMapper.xml    |  85 +--
 .../sharingprofile/SharingProfileMapper.xml     |  18 +-
 .../auth/jdbc/user/PasswordRecordMapper.xml     |   3 +-
 .../guacamole/auth/jdbc/user/UserMapper.xml     |  82 ++-
 .../jdbc/user/UserParentUserGroupMapper.xml     |  96 ++++
 .../auth/jdbc/user/UserRecordMapper.xml         |  29 +-
 .../auth/jdbc/usergroup/UserGroupMapper.xml     | 229 ++++++++
 .../UserGroupMemberUserGroupMapper.xml          |  93 ++++
 .../usergroup/UserGroupMemberUserMapper.xml     |  93 ++++
 .../UserGroupParentUserGroupMapper.xml          |  96 ++++
 .../schema/001-create-schema.sql                | 233 ++++++--
 .../schema/002-create-admin-user.sql            |  27 +-
 .../schema/upgrade/upgrade-pre-1.0.0.sql        | 357 +++++++++++++
 .../auth/postgresql/PostgreSQLEnvironment.java  |   6 +
 .../guacamole/auth/jdbc/base/EntityMapper.xml   | 123 +++++
 .../auth/jdbc/connection/ConnectionMapper.xml   |  30 +-
 .../jdbc/connection/ConnectionRecordMapper.xml  |  22 +-
 .../connectiongroup/ConnectionGroupMapper.xml   |  36 +-
 .../ConnectionGroupPermissionMapper.xml         |  48 +-
 .../permission/ConnectionPermissionMapper.xml   |  48 +-
 .../SharingProfilePermissionMapper.xml          |  48 +-
 .../jdbc/permission/SystemPermissionMapper.xml  |  44 +-
 .../permission/UserGroupPermissionMapper.xml    | 156 ++++++
 .../jdbc/permission/UserPermissionMapper.xml    |  89 ++--
 .../sharingprofile/SharingProfileMapper.xml     |  18 +-
 .../auth/jdbc/user/PasswordRecordMapper.xml     |   3 +-
 .../guacamole/auth/jdbc/user/UserMapper.xml     |  82 ++-
 .../jdbc/user/UserParentUserGroupMapper.xml     |  96 ++++
 .../auth/jdbc/user/UserRecordMapper.xml         |  29 +-
 .../auth/jdbc/usergroup/UserGroupMapper.xml     | 229 ++++++++
 .../UserGroupMemberUserGroupMapper.xml          |  93 ++++
 .../usergroup/UserGroupMemberUserMapper.xml     |  93 ++++
 .../UserGroupParentUserGroupMapper.xml          |  96 ++++
 .../schema/001-create-schema.sql                | 303 ++++++++---
 .../schema/002-create-admin-user.sql            |  21 +-
 .../schema/upgrade/upgrade-pre-1.0.0.sql        | 532 +++++++++++++++++++
 .../auth/sqlserver/SQLServerEnvironment.java    |   8 +-
 .../guacamole/auth/jdbc/base/EntityMapper.xml   | 127 +++++
 .../auth/jdbc/connection/ConnectionMapper.xml   |  30 +-
 .../jdbc/connection/ConnectionRecordMapper.xml  |  22 +-
 .../connectiongroup/ConnectionGroupMapper.xml   |  36 +-
 .../ConnectionGroupPermissionMapper.xml         |  52 +-
 .../permission/ConnectionPermissionMapper.xml   |  44 +-
 .../SharingProfilePermissionMapper.xml          |  44 +-
 .../jdbc/permission/SystemPermissionMapper.xml  |  40 +-
 .../permission/UserGroupPermissionMapper.xml    | 153 ++++++
 .../jdbc/permission/UserPermissionMapper.xml    | 100 ++--
 .../sharingprofile/SharingProfileMapper.xml     |  18 +-
 .../auth/jdbc/user/PasswordRecordMapper.xml     |   3 +-
 .../guacamole/auth/jdbc/user/UserMapper.xml     |  84 ++-
 .../jdbc/user/UserParentUserGroupMapper.xml     |  96 ++++
 .../auth/jdbc/user/UserRecordMapper.xml         |  29 +-
 .../auth/jdbc/usergroup/UserGroupMapper.xml     | 229 ++++++++
 .../UserGroupMemberUserGroupMapper.xml          |  93 ++++
 .../usergroup/UserGroupMemberUserMapper.xml     |  93 ++++
 .../UserGroupParentUserGroupMapper.xml          |  96 ++++
 133 files changed, 8377 insertions(+), 1132 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/82831354/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/pom.xml
----------------------------------------------------------------------


[38/38] guacamole-client git commit: Merge 1.0.0 changes back to master.

Posted by vn...@apache.org.
Merge 1.0.0 changes back to master.

Conflicts:
	extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java


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

Branch: refs/heads/master
Commit: 658ce7884695cbe0c04b29f0b6fa365312dbe2fd
Parents: 3ff5812 8283135
Author: Nick Couchman <vn...@apache.org>
Authored: Mon Oct 1 13:51:56 2018 -0400
Committer: Nick Couchman <vn...@apache.org>
Committed: Mon Oct 1 13:51:56 2018 -0400

----------------------------------------------------------------------
 .../modules/guacamole-auth-jdbc-base/pom.xml    |  10 +-
 .../jdbc/JDBCAuthenticationProviderModule.java  |  26 +
 .../guacamole/auth/jdbc/JDBCEnvironment.java    |  15 +
 .../ActiveConnectionPermissionService.java      |  51 +-
 .../guacamole/auth/jdbc/base/EntityMapper.java  |  80 +++
 .../guacamole/auth/jdbc/base/EntityModel.java   | 113 ++++
 .../guacamole/auth/jdbc/base/EntityService.java |  98 ++++
 .../guacamole/auth/jdbc/base/EntityType.java    |  38 ++
 .../ModeledChildDirectoryObjectService.java     |   7 +-
 .../jdbc/base/ModeledDirectoryObjectMapper.java |  14 +-
 .../base/ModeledDirectoryObjectService.java     |  22 +-
 .../auth/jdbc/base/ModeledPermissions.java      | 271 ++++++++++
 .../auth/jdbc/base/ObjectRelationMapper.java    | 126 +++++
 .../auth/jdbc/base/RelatedObjectSet.java        | 211 ++++++++
 .../auth/jdbc/connection/ConnectionMapper.java  |  10 +-
 .../jdbc/connection/ConnectionRecordMapper.java |   9 +-
 .../auth/jdbc/connection/ConnectionService.java |  19 +-
 .../connectiongroup/ConnectionGroupMapper.java  |  10 +-
 .../connectiongroup/ConnectionGroupService.java |  14 +-
 .../permission/AbstractPermissionService.java   |  59 +-
 .../ConnectionGroupPermissionService.java       |  11 +-
 .../permission/ConnectionPermissionService.java |  11 +-
 .../ModeledObjectPermissionService.java         |  98 ++--
 .../permission/ModeledPermissionService.java    |  44 +-
 .../jdbc/permission/ObjectPermissionMapper.java |  42 +-
 .../permission/ObjectPermissionService.java     |  49 +-
 .../jdbc/permission/ObjectPermissionSet.java    |  48 +-
 .../auth/jdbc/permission/PermissionMapper.java  |  20 +-
 .../auth/jdbc/permission/PermissionModel.java   |  50 +-
 .../auth/jdbc/permission/PermissionService.java |  67 ++-
 .../SharingProfilePermissionService.java        |  11 +-
 .../jdbc/permission/SystemPermissionMapper.java |  24 +-
 .../permission/SystemPermissionService.java     |  70 +--
 .../jdbc/permission/SystemPermissionSet.java    |  44 +-
 .../permission/UserGroupPermissionMapper.java   |  25 +
 .../permission/UserGroupPermissionService.java  |  67 +++
 .../jdbc/permission/UserGroupPermissionSet.java |  42 ++
 .../jdbc/permission/UserPermissionService.java  |  11 +-
 .../sharing/user/SharedAuthenticatedUser.java   |  11 +-
 .../sharingprofile/SharingProfileService.java   |  10 +-
 .../tunnel/AbstractGuacamoleTunnelService.java  |   4 +-
 .../jdbc/user/ModeledAuthenticatedUser.java     |   9 +-
 .../guacamole/auth/jdbc/user/ModeledUser.java   | 114 +---
 .../auth/jdbc/user/ModeledUserContext.java      |  16 +-
 .../auth/jdbc/user/RemoteAuthenticatedUser.java |  20 +-
 .../guacamole/auth/jdbc/user/UserMapper.java    |   2 +-
 .../guacamole/auth/jdbc/user/UserModel.java     |   6 +-
 .../jdbc/user/UserParentUserGroupMapper.java    |  28 +
 .../auth/jdbc/user/UserParentUserGroupSet.java  |  59 ++
 .../auth/jdbc/user/UserRecordMapper.java        |   9 +-
 .../guacamole/auth/jdbc/user/UserService.java   |  24 +-
 .../auth/jdbc/usergroup/ModeledUserGroup.java   | 206 +++++++
 .../auth/jdbc/usergroup/UserGroupDirectory.java |  82 +++
 .../auth/jdbc/usergroup/UserGroupMapper.java    |  42 ++
 .../UserGroupMemberUserGroupMapper.java         |  28 +
 .../usergroup/UserGroupMemberUserGroupSet.java  |  57 ++
 .../usergroup/UserGroupMemberUserMapper.java    |  28 +
 .../jdbc/usergroup/UserGroupMemberUserSet.java  |  57 ++
 .../auth/jdbc/usergroup/UserGroupModel.java     |  68 +++
 .../UserGroupParentUserGroupMapper.java         |  28 +
 .../usergroup/UserGroupParentUserGroupSet.java  |  58 ++
 .../auth/jdbc/usergroup/UserGroupService.java   | 183 +++++++
 .../src/main/resources/translations/en.json     |   8 +
 .../schema/001-create-schema.sql                | 196 +++++--
 .../schema/002-create-admin-user.sql            |  26 +-
 .../schema/upgrade/upgrade-pre-1.0.0.sql        | 335 ++++++++++++
 .../guacamole/auth/mysql/MySQLEnvironment.java  |  55 +-
 .../guacamole/auth/mysql/MySQLVersion.java      | 153 ++++++
 .../guacamole/auth/jdbc/base/EntityMapper.xml   | 156 ++++++
 .../auth/jdbc/connection/ConnectionMapper.xml   |  30 +-
 .../jdbc/connection/ConnectionRecordMapper.xml  |  22 +-
 .../connectiongroup/ConnectionGroupMapper.xml   |  36 +-
 .../ConnectionGroupPermissionMapper.xml         |  44 +-
 .../permission/ConnectionPermissionMapper.xml   |  44 +-
 .../SharingProfilePermissionMapper.xml          |  46 +-
 .../jdbc/permission/SystemPermissionMapper.xml  |  40 +-
 .../permission/UserGroupPermissionMapper.xml    | 149 ++++++
 .../jdbc/permission/UserPermissionMapper.xml    |  85 +--
 .../sharingprofile/SharingProfileMapper.xml     |  18 +-
 .../auth/jdbc/user/PasswordRecordMapper.xml     |   3 +-
 .../guacamole/auth/jdbc/user/UserMapper.xml     |  82 ++-
 .../jdbc/user/UserParentUserGroupMapper.xml     |  96 ++++
 .../auth/jdbc/user/UserRecordMapper.xml         |  29 +-
 .../auth/jdbc/usergroup/UserGroupMapper.xml     | 229 ++++++++
 .../UserGroupMemberUserGroupMapper.xml          |  93 ++++
 .../usergroup/UserGroupMemberUserMapper.xml     |  93 ++++
 .../UserGroupParentUserGroupMapper.xml          |  96 ++++
 .../schema/001-create-schema.sql                | 233 ++++++--
 .../schema/002-create-admin-user.sql            |  27 +-
 .../schema/upgrade/upgrade-pre-1.0.0.sql        | 357 +++++++++++++
 .../auth/postgresql/PostgreSQLEnvironment.java  |   6 +
 .../guacamole/auth/jdbc/base/EntityMapper.xml   | 123 +++++
 .../auth/jdbc/connection/ConnectionMapper.xml   |  30 +-
 .../jdbc/connection/ConnectionRecordMapper.xml  |  22 +-
 .../connectiongroup/ConnectionGroupMapper.xml   |  36 +-
 .../ConnectionGroupPermissionMapper.xml         |  48 +-
 .../permission/ConnectionPermissionMapper.xml   |  48 +-
 .../SharingProfilePermissionMapper.xml          |  48 +-
 .../jdbc/permission/SystemPermissionMapper.xml  |  44 +-
 .../permission/UserGroupPermissionMapper.xml    | 156 ++++++
 .../jdbc/permission/UserPermissionMapper.xml    |  89 ++--
 .../sharingprofile/SharingProfileMapper.xml     |  18 +-
 .../auth/jdbc/user/PasswordRecordMapper.xml     |   3 +-
 .../guacamole/auth/jdbc/user/UserMapper.xml     |  82 ++-
 .../jdbc/user/UserParentUserGroupMapper.xml     |  96 ++++
 .../auth/jdbc/user/UserRecordMapper.xml         |  29 +-
 .../auth/jdbc/usergroup/UserGroupMapper.xml     | 229 ++++++++
 .../UserGroupMemberUserGroupMapper.xml          |  93 ++++
 .../usergroup/UserGroupMemberUserMapper.xml     |  93 ++++
 .../UserGroupParentUserGroupMapper.xml          |  96 ++++
 .../schema/001-create-schema.sql                | 303 ++++++++---
 .../schema/002-create-admin-user.sql            |  21 +-
 .../schema/upgrade/upgrade-pre-1.0.0.sql        | 532 +++++++++++++++++++
 .../auth/sqlserver/SQLServerEnvironment.java    |   8 +-
 .../guacamole/auth/jdbc/base/EntityMapper.xml   | 127 +++++
 .../auth/jdbc/connection/ConnectionMapper.xml   |  30 +-
 .../jdbc/connection/ConnectionRecordMapper.xml  |  22 +-
 .../connectiongroup/ConnectionGroupMapper.xml   |  36 +-
 .../ConnectionGroupPermissionMapper.xml         |  52 +-
 .../permission/ConnectionPermissionMapper.xml   |  44 +-
 .../SharingProfilePermissionMapper.xml          |  44 +-
 .../jdbc/permission/SystemPermissionMapper.xml  |  40 +-
 .../permission/UserGroupPermissionMapper.xml    | 153 ++++++
 .../jdbc/permission/UserPermissionMapper.xml    | 100 ++--
 .../sharingprofile/SharingProfileMapper.xml     |  18 +-
 .../auth/jdbc/user/PasswordRecordMapper.xml     |   3 +-
 .../guacamole/auth/jdbc/user/UserMapper.xml     |  84 ++-
 .../jdbc/user/UserParentUserGroupMapper.xml     |  96 ++++
 .../auth/jdbc/user/UserRecordMapper.xml         |  29 +-
 .../auth/jdbc/usergroup/UserGroupMapper.xml     | 229 ++++++++
 .../UserGroupMemberUserGroupMapper.xml          |  93 ++++
 .../usergroup/UserGroupMemberUserMapper.xml     |  93 ++++
 .../UserGroupParentUserGroupMapper.xml          |  96 ++++
 133 files changed, 8377 insertions(+), 1132 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/658ce788/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/658ce788/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java
----------------------------------------------------------------------
diff --cc extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java
index f51d086,e756374..539cec0
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledAuthenticatedUser.java
@@@ -76,10 -76,9 +76,10 @@@ public class ModeledAuthenticatedUser e
       */
      public ModeledAuthenticatedUser(AuthenticatedUser authenticatedUser,
              AuthenticationProvider modelAuthenticationProvider, ModeledUser user) {
-         super(authenticatedUser.getAuthenticationProvider(), authenticatedUser.getCredentials());
+         super(authenticatedUser.getAuthenticationProvider(), authenticatedUser.getCredentials(), authenticatedUser.getEffectiveUserGroups());
          this.modelAuthenticationProvider = modelAuthenticationProvider;
          this.user = user;
 +        super.setAttributes(authenticatedUser.getAttributes());
      }
  
      /**

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/658ce788/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java
----------------------------------------------------------------------
diff --cc extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java
index 4cfceb2,324892e..d672719
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/RemoteAuthenticatedUser.java
@@@ -19,8 -19,8 +19,10 @@@
  
  package org.apache.guacamole.auth.jdbc.user;
  
 +import java.util.HashMap;
 +import java.util.Map;
+ import java.util.Collections;
+ import java.util.Set;
  import org.apache.guacamole.net.auth.AuthenticatedUser;
  import org.apache.guacamole.net.auth.AuthenticationProvider;
  import org.apache.guacamole.net.auth.Credentials;
@@@ -46,20 -46,11 +48,26 @@@ public abstract class RemoteAuthenticat
      private final String remoteHost;
  
      /**
 +     * Arbitrary attributes associated with this RemoteAuthenticatedUser object.
 +     */
 +    private Map<String, String> attributes = new HashMap<String, String>();
 +
++    /**
+      * The identifiers of any groups of which this user is a member, including
+      * groups inherited through membership in other groups.
+      */
+     private final Set<String> effectiveGroups;
+ 
 +    @Override
 +    public Map<String, String> getAttributes() {
 +        return attributes;
 +    }
 +
 +    @Override
 +    public void setAttributes(Map<String, String> attributes) {
 +        this.attributes = attributes;
 +    }
 +
      /**
       * Creates a new RemoteAuthenticatedUser, deriving the associated remote
       * host from the given credentials.
@@@ -67,11 -58,15 +75,15 @@@
       * @param authenticationProvider
       *     The AuthenticationProvider that has authenticated the given user.
       *
 -     * @param credentials 
 +     * @param credentials
       *     The credentials given by the user when they authenticated.
+      *
+      * @param effectiveGroups
+      *     The identifiers of any groups of which this user is a member,
+      *     including groups inherited through membership in other groups.
       */
      public RemoteAuthenticatedUser(AuthenticationProvider authenticationProvider,
-             Credentials credentials) {
+             Credentials credentials, Set<String> effectiveGroups) {
          this.authenticationProvider = authenticationProvider;
          this.credentials = credentials;
          this.remoteHost = credentials.getRemoteAddress();


[04/38] guacamole-client git commit: GUACAMOLE-220: Inherit from groups even if not determined by database.

Posted by vn...@apache.org.
GUACAMOLE-220: Inherit from groups even if not determined by database.


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

Branch: refs/heads/master
Commit: 14d10fb42abb59515bd58ce04245bd655be3b056
Parents: 6e71f33
Author: Michael Jumper <mj...@apache.org>
Authored: Fri Apr 6 14:10:52 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:51 2018 -0700

----------------------------------------------------------------------
 .../ActiveConnectionPermissionService.java      | 18 +++--
 .../jdbc/base/ModeledDirectoryObjectMapper.java | 14 +++-
 .../base/ModeledDirectoryObjectService.java     |  6 +-
 .../auth/jdbc/connection/ConnectionMapper.java  | 10 ++-
 .../jdbc/connection/ConnectionRecordMapper.java |  9 ++-
 .../auth/jdbc/connection/ConnectionService.java |  9 ++-
 .../connectiongroup/ConnectionGroupMapper.java  | 10 ++-
 .../connectiongroup/ConnectionGroupService.java |  4 +-
 .../ConnectionGroupPermissionService.java       |  6 +-
 .../permission/ConnectionPermissionService.java |  6 +-
 .../ModeledObjectPermissionService.java         | 15 +++--
 .../permission/ModeledPermissionService.java    |  5 +-
 .../jdbc/permission/ObjectPermissionMapper.java | 22 +++---
 .../permission/ObjectPermissionService.java     | 23 ++++---
 .../jdbc/permission/ObjectPermissionSet.java    | 25 +++----
 .../auth/jdbc/permission/PermissionMapper.java  | 11 +--
 .../auth/jdbc/permission/PermissionService.java | 24 ++++---
 .../SharingProfilePermissionService.java        |  6 +-
 .../jdbc/permission/SystemPermissionMapper.java | 12 ++--
 .../permission/SystemPermissionService.java     | 18 ++---
 .../jdbc/permission/SystemPermissionSet.java    | 23 +++----
 .../jdbc/permission/UserPermissionService.java  |  6 +-
 .../tunnel/AbstractGuacamoleTunnelService.java  |  4 +-
 .../guacamole/auth/jdbc/user/ModeledUser.java   | 52 +++++++++-----
 .../guacamole/auth/jdbc/user/UserMapper.java    | 24 ++++++-
 .../auth/jdbc/user/UserRecordMapper.java        |  9 ++-
 .../guacamole/auth/jdbc/user/UserService.java   | 29 +++++++-
 .../guacamole/auth/jdbc/base/EntityMapper.xml   | 49 +++++++++-----
 .../auth/jdbc/connection/ConnectionMapper.xml   | 55 +++++++--------
 .../jdbc/connection/ConnectionRecordMapper.xml  | 22 +++---
 .../connectiongroup/ConnectionGroupMapper.xml   | 66 +++++++++---------
 .../ConnectionGroupPermissionMapper.xml         | 33 +++++----
 .../permission/ConnectionPermissionMapper.xml   | 33 +++++----
 .../SharingProfilePermissionMapper.xml          | 34 +++++-----
 .../jdbc/permission/SystemPermissionMapper.xml  | 22 +++---
 .../jdbc/permission/UserPermissionMapper.xml    | 33 +++++----
 .../sharingprofile/SharingProfileMapper.xml     | 33 +++++----
 .../guacamole/auth/jdbc/user/UserMapper.xml     | 71 +++++++++++++++-----
 .../auth/jdbc/user/UserRecordMapper.xml         | 11 ++-
 39 files changed, 514 insertions(+), 348 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java
index 405b237..a0511b8 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/activeconnection/ActiveConnectionPermissionService.java
@@ -59,10 +59,11 @@ public class ActiveConnectionPermissionService
     @Override
     public boolean hasPermission(ModeledAuthenticatedUser user,
             ModeledUser targetUser, ObjectPermission.Type type,
-            String identifier, boolean inherit) throws GuacamoleException {
+            String identifier, Set<String> effectiveGroups) throws GuacamoleException {
 
         // Retrieve permissions
-        Set<ObjectPermission> permissions = retrievePermissions(user, targetUser, inherit);
+        Set<ObjectPermission> permissions = retrievePermissions(user,
+                targetUser, effectiveGroups);
 
         // Permission is granted if retrieved permissions contains the
         // requested permission
@@ -73,7 +74,8 @@ public class ActiveConnectionPermissionService
 
     @Override
     public Set<ObjectPermission> retrievePermissions(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, boolean inherit) throws GuacamoleException {
+            ModeledUser targetUser, Set<String> effectiveGroups)
+            throws GuacamoleException {
 
         // Retrieve permissions only if allowed
         if (canReadPermissions(user, targetUser)) {
@@ -109,9 +111,10 @@ public class ActiveConnectionPermissionService
     @Override
     public Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user,
             ModeledUser targetUser, Collection<ObjectPermission.Type> permissionTypes,
-            Collection<String> identifiers, boolean inherit) throws GuacamoleException {
+            Collection<String> identifiers, Set<String> effectiveGroups)
+            throws GuacamoleException {
 
-        Set<ObjectPermission> permissions = retrievePermissions(user, targetUser, inherit);
+        Set<ObjectPermission> permissions = retrievePermissions(user, targetUser, effectiveGroups);
         Collection<String> accessibleObjects = new ArrayList<String>(permissions.size());
 
         // For each identifier/permission combination
@@ -134,11 +137,12 @@ public class ActiveConnectionPermissionService
 
     @Override
     public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, boolean inherit) throws GuacamoleException {
+            ModeledUser targetUser, Set<String> effectiveGroups)
+            throws GuacamoleException {
     
         // Create permission set for requested user
         ActiveConnectionPermissionSet permissionSet = activeConnectionPermissionSetProvider.get();
-        permissionSet.init(user, targetUser, inherit);
+        permissionSet.init(user, targetUser, effectiveGroups);
 
         return permissionSet;
  

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectMapper.java
index 4431e8f..8ff0cc1 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectMapper.java
@@ -57,10 +57,15 @@ public interface ModeledDirectoryObjectMapper<ModelType> {
      *    The user whose permissions should determine whether an identifier
      *    is returned.
      *
+     * @param effectiveGroups
+     *     The identifiers of any known effective groups that should be taken
+     *     into account, such as those defined externally to the database.
+     *
      * @return
      *     A Set containing all identifiers of all readable objects.
      */
-    Set<String> selectReadableIdentifiers(@Param("user") UserModel user);
+    Set<String> selectReadableIdentifiers(@Param("user") UserModel user,
+            @Param("effectiveGroups") Collection<String> effectiveGroups);
     
     /**
      * Selects all objects which have the given identifiers. If an identifier
@@ -91,11 +96,16 @@ public interface ModeledDirectoryObjectMapper<ModelType> {
      * @param identifiers
      *     The identifiers of the objects to return.
      *
+     * @param effectiveGroups
+     *     The identifiers of any known effective groups that should be taken
+     *     into account, such as those defined externally to the database.
+     *
      * @return 
      *     A Collection of all objects having the given identifiers.
      */
     Collection<ModelType> selectReadable(@Param("user") UserModel user,
-            @Param("identifiers") Collection<String> identifiers);
+            @Param("identifiers") Collection<String> identifiers,
+            @Param("effectiveGroups") Collection<String> effectiveGroups);
 
     /**
      * Inserts the given object into the database. If the object already

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java
index e87d664..edbb67e 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java
@@ -401,7 +401,8 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
 
         // Otherwise only return explicitly readable identifiers
         else
-            objects = getObjectMapper().selectReadable(user.getUser().getModel(), identifiers);
+            objects = getObjectMapper().selectReadable(user.getUser().getModel(),
+                    identifiers, user.getEffectiveUserGroups());
         
         // Return collection of requested objects
         return getObjectInstances(user, objects);
@@ -512,7 +513,8 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
 
         // Otherwise only return explicitly readable identifiers
         else
-            return getObjectMapper().selectReadableIdentifiers(user.getUser().getModel());
+            return getObjectMapper().selectReadableIdentifiers(user.getUser().getModel(),
+                    user.getEffectiveUserGroups());
 
     }
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.java
index 9a49132..3cd542f 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.java
@@ -19,6 +19,7 @@
 
 package org.apache.guacamole.auth.jdbc.connection;
 
+import java.util.Collection;
 import java.util.Set;
 import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
 import org.apache.guacamole.auth.jdbc.user.UserModel;
@@ -61,11 +62,18 @@ public interface ConnectionMapper extends ModeledDirectoryObjectMapper<Connectio
      *     The identifier of the parent connection group, or null if the root
      *     connection group is to be queried.
      *
+     * @param effectiveGroups
+     *     The identifiers of all groups that should be taken into account
+     *     when determining the permissions effectively granted to the user. If
+     *     no groups are given, only permissions directly granted to the user
+     *     will be used.
+     *
      * @return
      *     A Set containing all identifiers of all readable objects.
      */
     Set<String> selectReadableIdentifiersWithin(@Param("user") UserModel user,
-            @Param("parentIdentifier") String parentIdentifier);
+            @Param("parentIdentifier") String parentIdentifier,
+            @Param("effectiveGroups") Collection<String> effectiveGroups);
 
     /**
      * Selects the connection within the given parent group and having the

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java
index 637fd0f..7380b21 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java
@@ -102,12 +102,19 @@ public interface ConnectionRecordMapper {
      * @param limit
      *     The maximum number of records that should be returned.
      *
+     * @param effectiveGroups
+     *     The identifiers of all groups that should be taken into account
+     *     when determining the permissions effectively granted to the user. If
+     *     no groups are given, only permissions directly granted to the user
+     *     will be used.
+     *
      * @return
      *     The results of the search performed with the given parameters.
      */
     List<ConnectionRecordModel> searchReadable(@Param("user") UserModel user,
             @Param("terms") Collection<ActivityRecordSearchTerm> terms,
             @Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
-            @Param("limit") int limit);
+            @Param("limit") int limit,
+            @Param("effectiveGroups") Collection<String> effectiveGroups);
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java
index 11e3792..8dcf6f5 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java
@@ -303,7 +303,9 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
 
         // Otherwise only return explicitly readable identifiers
         else
-            return connectionMapper.selectReadableIdentifiersWithin(user.getUser().getModel(), identifier);
+            return connectionMapper.selectReadableIdentifiersWithin(
+                    user.getUser().getModel(), identifier,
+                    user.getEffectiveUserGroups());
 
     }
 
@@ -475,8 +477,9 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
 
         // Otherwise only return explicitly readable history records
         else
-            searchResults = connectionRecordMapper.searchReadable(user.getUser().getModel(),
-                    requiredContents, sortPredicates, limit);
+            searchResults = connectionRecordMapper.searchReadable(
+                    user.getUser().getModel(), requiredContents, sortPredicates,
+                    limit, user.getEffectiveUserGroups());
 
         return getObjectInstances(searchResults);
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.java
index c82069a..a54a151 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.java
@@ -19,6 +19,7 @@
 
 package org.apache.guacamole.auth.jdbc.connectiongroup;
 
+import java.util.Collection;
 import java.util.Set;
 import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
 import org.apache.guacamole.auth.jdbc.user.UserModel;
@@ -61,11 +62,18 @@ public interface ConnectionGroupMapper extends ModeledDirectoryObjectMapper<Conn
      *     The identifier of the parent connection group, or null if the root
      *     connection group is to be queried.
      *
+     * @param effectiveGroups
+     *     The identifiers of all groups that should be taken into account
+     *     when determining the permissions effectively granted to the user. If
+     *     no groups are given, only permissions directly granted to the user
+     *     will be used.
+     *
      * @return
      *     A Set containing all identifiers of all readable objects.
      */
     Set<String> selectReadableIdentifiersWithin(@Param("user") UserModel user,
-            @Param("parentIdentifier") String parentIdentifier);
+            @Param("parentIdentifier") String parentIdentifier,
+            @Param("effectiveGroups") Collection<String> effectiveGroups);
 
     /**
      * Selects the connection group within the given parent group and having

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java
index 34d039c..01119b9 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java
@@ -223,7 +223,9 @@ public class ConnectionGroupService extends ModeledChildDirectoryObjectService<M
 
         // Otherwise only return explicitly readable identifiers
         else
-            return connectionGroupMapper.selectReadableIdentifiersWithin(user.getUser().getModel(), identifier);
+            return connectionGroupMapper.selectReadableIdentifiersWithin(
+                    user.getUser().getModel(), identifier,
+                    user.getEffectiveUserGroups());
 
     }
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java
index 3027d81..afabbc7 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionService.java
@@ -21,6 +21,7 @@ package org.apache.guacamole.auth.jdbc.permission;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.auth.jdbc.user.ModeledUser;
@@ -51,11 +52,12 @@ public class ConnectionGroupPermissionService extends ModeledObjectPermissionSer
 
     @Override
     public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, boolean inherit) throws GuacamoleException {
+            ModeledUser targetUser, Set<String> effectiveGroups)
+            throws GuacamoleException {
 
         // Create permission set for requested user
         ObjectPermissionSet permissionSet = connectionGroupPermissionSetProvider.get();
-        permissionSet.init(user, targetUser, inherit);
+        permissionSet.init(user, targetUser, effectiveGroups);
 
         return permissionSet;
         

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java
index 19c30c0..0cc69df 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionService.java
@@ -21,6 +21,7 @@ package org.apache.guacamole.auth.jdbc.permission;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.auth.jdbc.user.ModeledUser;
@@ -51,11 +52,12 @@ public class ConnectionPermissionService extends ModeledObjectPermissionService
 
     @Override
     public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, boolean inherit) throws GuacamoleException {
+            ModeledUser targetUser, Set<String> effectiveGroups)
+            throws GuacamoleException {
 
         // Create permission set for requested user
         ObjectPermissionSet permissionSet = connectionPermissionSetProvider.get();
-        permissionSet.init(user, targetUser, inherit);
+        permissionSet.init(user, targetUser, effectiveGroups);
 
         return permissionSet;
         

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
index b1229ae..f1105ed 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledObjectPermissionService.java
@@ -22,6 +22,7 @@ package org.apache.guacamole.auth.jdbc.permission;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
 import org.apache.guacamole.auth.jdbc.user.ModeledUser;
 import org.apache.guacamole.GuacamoleException;
@@ -106,7 +107,7 @@ public abstract class ModeledObjectPermissionService
             affectedIdentifiers.add(permission.getObjectIdentifier());
 
         // Determine subset of affected identifiers that we have admin access to
-        ObjectPermissionSet affectedPermissionSet = getPermissionSet(user, user.getUser(), true);
+        ObjectPermissionSet affectedPermissionSet = getPermissionSet(user, user.getUser(), user.getEffectiveUserGroups());
         Collection<String> allowedSubset = affectedPermissionSet.getAccessibleObjects(
             Collections.singleton(ObjectPermission.Type.ADMINISTER),
             affectedIdentifiers
@@ -157,11 +158,13 @@ public abstract class ModeledObjectPermissionService
     @Override
     public boolean hasPermission(ModeledAuthenticatedUser user,
             ModeledUser targetUser, ObjectPermission.Type type,
-            String identifier, boolean inherit) throws GuacamoleException {
+            String identifier, Set<String> effectiveGroups)
+            throws GuacamoleException {
 
         // Retrieve permissions only if allowed
         if (canReadPermissions(user, targetUser))
-            return getPermissionMapper().selectOne(targetUser.getModel(), type, identifier, inherit) != null;
+            return getPermissionMapper().selectOne(targetUser.getModel(), type,
+                    identifier, effectiveGroups) != null;
 
         // User cannot read this user's permissions
         throw new GuacamoleSecurityException("Permission denied.");
@@ -171,7 +174,7 @@ public abstract class ModeledObjectPermissionService
     @Override
     public Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user,
             ModeledUser targetUser, Collection<ObjectPermission.Type> permissions,
-            Collection<String> identifiers, boolean inherit)
+            Collection<String> identifiers, Set<String> effectiveGroups)
             throws GuacamoleException {
 
         // Nothing is always accessible
@@ -186,7 +189,9 @@ public abstract class ModeledObjectPermissionService
                 return identifiers;
 
             // Otherwise, return explicitly-retrievable identifiers
-            return getPermissionMapper().selectAccessibleIdentifiers(targetUser.getModel(), permissions, identifiers, inherit);
+            return getPermissionMapper().selectAccessibleIdentifiers(
+                    targetUser.getModel(), permissions, identifiers,
+                    effectiveGroups);
             
         }
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java
index 4d0fcf6..dadaea6 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ModeledPermissionService.java
@@ -140,11 +140,12 @@ public abstract class ModeledPermissionService<PermissionSetType extends Permiss
 
     @Override
     public Set<PermissionType> retrievePermissions(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, boolean inherit) throws GuacamoleException {
+            ModeledUser targetUser, Set<String> effectiveGroups)
+            throws GuacamoleException {
 
         // Retrieve permissions only if allowed
         if (canReadPermissions(user, targetUser))
-            return getPermissionInstances(getPermissionMapper().select(targetUser.getModel(), inherit));
+            return getPermissionInstances(getPermissionMapper().select(targetUser.getModel(), effectiveGroups));
 
         // User cannot read this user's permissions
         throw new GuacamoleSecurityException("Permission denied.");

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java
index e5efad0..b6f9801 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionMapper.java
@@ -43,10 +43,11 @@ public interface ObjectPermissionMapper extends PermissionMapper<ObjectPermissio
      * @param identifier
      *     The identifier of the object affected by the permission to return.
      *
-     * @param inherit
-     *     Whether permissions inherited through user groups should be taken
-     *     into account. If false, only permissions granted directly will be
-     *     included.
+     * @param effectiveGroups
+     *     The identifiers of all groups that should be taken into account
+     *     when determining the permissions effectively granted to the user. If
+     *     no groups are given, only permissions directly granted to the user
+     *     will be used.
      *
      * @return
      *     The requested permission, or null if no such permission is granted
@@ -55,7 +56,7 @@ public interface ObjectPermissionMapper extends PermissionMapper<ObjectPermissio
     ObjectPermissionModel selectOne(@Param("entity") EntityModel entity,
             @Param("type") ObjectPermission.Type type,
             @Param("identifier") String identifier,
-            @Param("inherit") boolean inherit);
+            @Param("effectiveGroups") Collection<String> effectiveGroups);
 
     /**
      * Retrieves the subset of the given identifiers for which the given entity
@@ -73,10 +74,11 @@ public interface ObjectPermissionMapper extends PermissionMapper<ObjectPermissio
      *     The identifiers of the objects affected by the permissions being
      *     checked.
      *
-     * @param inherit
-     *     Whether permissions inherited through user groups should be taken
-     *     into account. If false, only permissions granted directly will be
-     *     included.
+     * @param effectiveGroups
+     *     The identifiers of all groups that should be taken into account
+     *     when determining the permissions effectively granted to the user. If
+     *     no groups are given, only permissions directly granted to the user
+     *     will be used.
      *
      * @return
      *     A collection containing the subset of identifiers for which at least
@@ -85,6 +87,6 @@ public interface ObjectPermissionMapper extends PermissionMapper<ObjectPermissio
     Collection<String> selectAccessibleIdentifiers(@Param("entity") EntityModel entity,
             @Param("permissions") Collection<ObjectPermission.Type> permissions,
             @Param("identifiers") Collection<String> identifiers,
-            @Param("inherit") boolean inherit);
+            @Param("effectiveGroups") Collection<String> effectiveGroups);
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java
index fa1ee2d..3f39881 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionService.java
@@ -20,6 +20,7 @@
 package org.apache.guacamole.auth.jdbc.permission;
 
 import java.util.Collection;
+import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
 import org.apache.guacamole.auth.jdbc.user.ModeledUser;
 import org.apache.guacamole.GuacamoleException;
@@ -50,10 +51,11 @@ public interface ObjectPermissionService
      * @param identifier
      *     The identifier of the object affected by the permission to return.
      *
-     * @param inherit
-     *     Whether permissions inherited through user groups should be taken
-     *     into account. If false, only permissions granted directly will be
-     *     included.
+     * @param effectiveGroups
+     *     The identifiers of all groups that should be taken into account
+     *     when determining the permissions effectively granted to the user. If
+     *     no groups are given, only permissions directly granted to the user
+     *     will be used.
      *
      * @return
      *     true if permission of the given type and associated with the given
@@ -64,7 +66,7 @@ public interface ObjectPermissionService
      */
     boolean hasPermission(ModeledAuthenticatedUser user,
             ModeledUser targetUser, ObjectPermission.Type type,
-            String identifier, boolean inherit) throws GuacamoleException;
+            String identifier, Set<String> effectiveGroups) throws GuacamoleException;
 
     /**
      * Retrieves the subset of the given identifiers for which the given user
@@ -85,10 +87,11 @@ public interface ObjectPermissionService
      *     The identifiers of the objects affected by the permissions being
      *     checked.
      *
-     * @param inherit
-     *     Whether permissions inherited through user groups should be taken
-     *     into account. If false, only permissions granted directly will be
-     *     included.
+     * @param effectiveGroups
+     *     The identifiers of all groups that should be taken into account
+     *     when determining the permissions effectively granted to the user. If
+     *     no groups are given, only permissions directly granted to the user
+     *     will be used.
      *
      * @return
      *     A collection containing the subset of identifiers for which at least
@@ -99,7 +102,7 @@ public interface ObjectPermissionService
      */
     Collection<String> retrieveAccessibleIdentifiers(ModeledAuthenticatedUser user,
             ModeledUser targetUser, Collection<ObjectPermission.Type> permissions,
-            Collection<String> identifiers, boolean inherit)
+            Collection<String> identifiers, Set<String> effectiveGroups)
             throws GuacamoleException;
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java
index cedb45d..c15b1af 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/ObjectPermissionSet.java
@@ -42,11 +42,7 @@ public abstract class ObjectPermissionSet extends RestrictedObject
      */
     private ModeledUser user;
 
-    /**
-     * Whether permissions inherited through user groups should be taken into
-     * account. If false, only permissions granted directly will be included.
-     */
-    boolean inherit;
+    private Set<String> effectiveGroups;
 
     /**
      * Creates a new ObjectPermissionSet. The resulting permission set
@@ -67,16 +63,17 @@ public abstract class ObjectPermissionSet extends RestrictedObject
      * @param user
      *     The user to whom the permissions in this set are granted.
      *
-     * @param inherit
-     *     Whether permissions inherited through user groups should be taken
-     *     into account. If false, only permissions granted directly will be
-     *     included.
+     * @param effectiveGroups
+     *     The identifiers of all groups that should be taken into account
+     *     when determining the permissions effectively granted to the user. If
+     *     no groups are given, only permissions directly granted to the user
+     *     will be used.
      */
     public void init(ModeledAuthenticatedUser currentUser, ModeledUser user,
-            boolean inherit) {
+            Set<String> effectiveGroups) {
         super.init(currentUser);
         this.user = user;
-        this.inherit = inherit;
+        this.effectiveGroups = effectiveGroups;
     }
 
     /**
@@ -91,13 +88,13 @@ public abstract class ObjectPermissionSet extends RestrictedObject
 
     @Override
     public Set<ObjectPermission> getPermissions() throws GuacamoleException {
-        return getObjectPermissionService().retrievePermissions(getCurrentUser(), user, inherit);
+        return getObjectPermissionService().retrievePermissions(getCurrentUser(), user, effectiveGroups);
     }
 
     @Override
     public boolean hasPermission(ObjectPermission.Type permission,
             String identifier) throws GuacamoleException {
-        return getObjectPermissionService().hasPermission(getCurrentUser(), user, permission, identifier, inherit);
+        return getObjectPermissionService().hasPermission(getCurrentUser(), user, permission, identifier, effectiveGroups);
     }
 
     @Override
@@ -115,7 +112,7 @@ public abstract class ObjectPermissionSet extends RestrictedObject
     @Override
     public Collection<String> getAccessibleObjects(Collection<ObjectPermission.Type> permissions,
             Collection<String> identifiers) throws GuacamoleException {
-        return getObjectPermissionService().retrieveAccessibleIdentifiers(getCurrentUser(), user, permissions, identifiers, inherit);
+        return getObjectPermissionService().retrieveAccessibleIdentifiers(getCurrentUser(), user, permissions, identifiers, effectiveGroups);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java
index 1c2d23b..edd66f4 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionMapper.java
@@ -38,16 +38,17 @@ public interface PermissionMapper<PermissionType> {
      * @param entity
      *     The entity to retrieve permissions for.
      *
-     * @param inherit
-     *     Whether permissions inherited through user groups should be taken
-     *     into account. If false, only permissions granted directly will be
-     *     included.
+     * @param effectiveGroups
+     *     The identifiers of all groups that should be taken into account
+     *     when determining the permissions effectively granted to the user. If
+     *     no groups are given, only permissions directly granted to the user
+     *     will be used.
      *
      * @return
      *     All permissions associated with the given entity.
      */
     Collection<PermissionType> select(@Param("entity") EntityModel entity,
-            @Param("inherit") boolean inherit);
+            @Param("effectiveGroups") Collection<String> effectiveGroups);
 
     /**
      * Inserts the given permissions into the database. If any permissions

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java
index 6e59634..3caa587 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java
@@ -54,10 +54,11 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
      *     The user to whom the permissions in the returned permission set are
      *     granted.
      *
-     * @param inherit
-     *     Whether permissions inherited through user groups should be taken
-     *     into account. If false, only permissions granted directly will be
-     *     included.
+     * @param effectiveGroups
+     *     The identifiers of all groups that should be taken into account
+     *     when determining the permissions effectively granted to the user. If
+     *     no groups are given, only permissions directly granted to the user
+     *     will be used.
      *
      * @return
      *     A permission set that contains all permissions associated with the
@@ -69,7 +70,8 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
      *     user is denied.
      */
     PermissionSetType getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, boolean inherit) throws GuacamoleException;
+            ModeledUser targetUser, Set<String> effectiveGroups)
+            throws GuacamoleException;
 
     /**
      * Retrieves all permissions associated with the given user.
@@ -80,10 +82,11 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
      * @param targetUser
      *     The user associated with the permissions to be retrieved.
      *
-     * @param inherit
-     *     Whether permissions inherited through user groups should be taken
-     *     into account. If false, only permissions granted directly will be
-     *     included.
+     * @param effectiveGroups
+     *     The identifiers of all groups that should be taken into account
+     *     when determining the permissions effectively granted to the user. If
+     *     no groups are given, only permissions directly granted to the user
+     *     will be used.
      *
      * @return
      *     The permissions associated with the given user.
@@ -92,7 +95,8 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
      *     If an error occurs while retrieving the requested permissions.
      */
     Set<PermissionType> retrievePermissions(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, boolean inherit) throws GuacamoleException;
+            ModeledUser targetUser, Set<String> effectiveGroups)
+            throws GuacamoleException;
 
     /**
      * Creates the given permissions within the database. If any permissions

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java
index 3cdf9d1..3018b29 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionService.java
@@ -21,6 +21,7 @@ package org.apache.guacamole.auth.jdbc.permission;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.auth.jdbc.user.ModeledUser;
@@ -51,11 +52,12 @@ public class SharingProfilePermissionService extends ModeledObjectPermissionServ
 
     @Override
     public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, boolean inherit) throws GuacamoleException {
+            ModeledUser targetUser, Set<String> effectiveGroups)
+            throws GuacamoleException {
 
         // Create permission set for requested user
         ObjectPermissionSet permissionSet = sharingProfilePermissionSetProvider.get();
-        permissionSet.init(user, targetUser, inherit);
+        permissionSet.init(user, targetUser, effectiveGroups);
 
         return permissionSet;
         

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java
index c05f405..c676b72 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.java
@@ -19,6 +19,7 @@
 
 package org.apache.guacamole.auth.jdbc.permission;
 
+import java.util.Collection;
 import org.apache.guacamole.auth.jdbc.base.EntityModel;
 import org.apache.ibatis.annotations.Param;
 import org.apache.guacamole.net.auth.permission.SystemPermission;
@@ -38,10 +39,11 @@ public interface SystemPermissionMapper extends PermissionMapper<SystemPermissio
      * @param type
      *     The type of permission to return.
      *
-     * @param inherit
-     *     Whether permissions inherited through user groups should be taken
-     *     into account. If false, only permissions granted directly will be
-     *     included.
+     * @param effectiveGroups
+     *     The identifiers of all groups that should be taken into account
+     *     when determining the permissions effectively granted to the user. If
+     *     no groups are given, only permissions directly granted to the user
+     *     will be used.
      *
      * @return
      *     The requested permission, or null if no such permission is granted
@@ -49,6 +51,6 @@ public interface SystemPermissionMapper extends PermissionMapper<SystemPermissio
      */
     SystemPermissionModel selectOne(@Param("entity") EntityModel entity,
             @Param("type") SystemPermission.Type type,
-            @Param("inherit") boolean inherit);
+            @Param("effectiveGroups") Collection<String> effectiveGroups);
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
index 5909569..b534ad3 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
@@ -22,6 +22,7 @@ package org.apache.guacamole.auth.jdbc.permission;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 import java.util.Collection;
+import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
 import org.apache.guacamole.auth.jdbc.user.ModeledUser;
 import org.apache.guacamole.GuacamoleException;
@@ -75,11 +76,11 @@ public class SystemPermissionService
 
     @Override
     public SystemPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, boolean inherit) throws GuacamoleException {
+            ModeledUser targetUser, Set<String> effectiveGroups) throws GuacamoleException {
 
         // Create permission set for requested user
         SystemPermissionSet permissionSet = systemPermissionSetProvider.get();
-        permissionSet.init(user, targetUser, inherit);
+        permissionSet.init(user, targetUser, effectiveGroups);
 
         return permissionSet;
         
@@ -136,10 +137,11 @@ public class SystemPermissionService
      * @param type
      *     The type of permission to retrieve.
      *
-     * @param inherit
-     *     Whether permissions inherited through user groups should be taken
-     *     into account. If false, only permissions granted directly will be
-     *     included.
+     * @param effectiveGroups
+     *     The identifiers of all groups that should be taken into account
+     *     when determining the permissions effectively granted to the user. If
+     *     no groups are given, only permissions directly granted to the user
+     *     will be used.
      *
      * @return
      *     true if permission of the given type has been granted to the given
@@ -150,11 +152,11 @@ public class SystemPermissionService
      */
     public boolean hasPermission(ModeledAuthenticatedUser user,
             ModeledUser targetUser, SystemPermission.Type type,
-            boolean inherit) throws GuacamoleException {
+            Set<String> effectiveGroups) throws GuacamoleException {
 
         // Retrieve permissions only if allowed
         if (canReadPermissions(user, targetUser))
-            return getPermissionMapper().selectOne(targetUser.getModel(), type, inherit) != null;
+            return getPermissionMapper().selectOne(targetUser.getModel(), type, effectiveGroups) != null;
 
         // User cannot read this user's permissions
         throw new GuacamoleSecurityException("Permission denied.");

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java
index bb5af11..dd88879 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionSet.java
@@ -42,11 +42,7 @@ public class SystemPermissionSet extends RestrictedObject
      */
     private ModeledUser user;
 
-    /**
-     * Whether permissions inherited through user groups should be taken into
-     * account. If false, only permissions granted directly will be included.
-     */
-    private boolean inherit;
+    private Set<String> effectiveGroups;
 
     /**
      * Service for reading and manipulating system permissions.
@@ -73,27 +69,28 @@ public class SystemPermissionSet extends RestrictedObject
      * @param user
      *     The user to whom the permissions in this set are granted.
      *
-     * @param inherit
-     *     Whether permissions inherited through user groups should be taken
-     *     into account. If false, only permissions granted directly will be
-     *     included.
+     * @param effectiveGroups
+     *     The identifiers of all groups that should be taken into account
+     *     when determining the permissions effectively granted to the user. If
+     *     no groups are given, only permissions directly granted to the user
+     *     will be used.
      */
     public void init(ModeledAuthenticatedUser currentUser, ModeledUser user,
-            boolean inherit) {
+            Set<String> effectiveGroups) {
         super.init(currentUser);
         this.user = user;
-        this.inherit = inherit;
+        this.effectiveGroups = effectiveGroups;
     }
 
     @Override
     public Set<SystemPermission> getPermissions() throws GuacamoleException {
-        return systemPermissionService.retrievePermissions(getCurrentUser(), user, inherit);
+        return systemPermissionService.retrievePermissions(getCurrentUser(), user, effectiveGroups);
     }
 
     @Override
     public boolean hasPermission(SystemPermission.Type permission)
             throws GuacamoleException {
-        return systemPermissionService.hasPermission(getCurrentUser(), user, permission, inherit);
+        return systemPermissionService.hasPermission(getCurrentUser(), user, permission, effectiveGroups);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java
index 8e65862..fabbf72 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/UserPermissionService.java
@@ -21,6 +21,7 @@ package org.apache.guacamole.auth.jdbc.permission;
 
 import com.google.inject.Inject;
 import com.google.inject.Provider;
+import java.util.Set;
 import org.apache.guacamole.auth.jdbc.user.ModeledAuthenticatedUser;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.auth.jdbc.user.ModeledUser;
@@ -51,11 +52,12 @@ public class UserPermissionService extends ModeledObjectPermissionService {
 
     @Override
     public ObjectPermissionSet getPermissionSet(ModeledAuthenticatedUser user,
-            ModeledUser targetUser, boolean inherit) throws GuacamoleException {
+            ModeledUser targetUser, Set<String> effectiveGroups)
+            throws GuacamoleException {
 
         // Create permission set for requested user
         ObjectPermissionSet permissionSet = userPermissionSetProvider.get();
-        permissionSet.init(user, targetUser, inherit);
+        permissionSet.init(user, targetUser, effectiveGroups);
 
         return permissionSet;
         

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/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 fe3a45b..5f7fc1b 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
@@ -628,7 +628,9 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS
             identifiers.add(record.getConnection().getIdentifier());
 
         // Produce collection of readable connection identifiers
-        Collection<ConnectionModel> connections = connectionMapper.selectReadable(user.getUser().getModel(), identifiers);
+        Collection<ConnectionModel> connections =
+                connectionMapper.selectReadable(user.getUser().getModel(),
+                        identifiers, user.getEffectiveUserGroups());
 
         // Ensure set contains only identifiers of readable connections
         identifiers.clear();

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
index 0628d74..0bb199e 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java
@@ -351,37 +351,43 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
     @Override
     public SystemPermissionSet getSystemPermissions()
             throws GuacamoleException {
-        return systemPermissionService.getPermissionSet(getCurrentUser(), this, false);
+        return systemPermissionService.getPermissionSet(getCurrentUser(), this,
+                Collections.<String>emptySet());
     }
 
     @Override
     public ObjectPermissionSet getConnectionPermissions()
             throws GuacamoleException {
-        return connectionPermissionService.getPermissionSet(getCurrentUser(), this, false);
+        return connectionPermissionService.getPermissionSet(getCurrentUser(),
+                this, Collections.<String>emptySet());
     }
 
     @Override
     public ObjectPermissionSet getConnectionGroupPermissions()
             throws GuacamoleException {
-        return connectionGroupPermissionService.getPermissionSet(getCurrentUser(), this, false);
+        return connectionGroupPermissionService.getPermissionSet(
+                getCurrentUser(), this, Collections.<String>emptySet());
     }
 
     @Override
     public ObjectPermissionSet getSharingProfilePermissions()
             throws GuacamoleException {
-        return sharingProfilePermissionService.getPermissionSet(getCurrentUser(), this, false);
+        return sharingProfilePermissionService.getPermissionSet(
+                getCurrentUser(), this, Collections.<String>emptySet());
     }
 
     @Override
     public ObjectPermissionSet getActiveConnectionPermissions()
             throws GuacamoleException {
-        return activeConnectionPermissionService.getPermissionSet(getCurrentUser(), this, false);
+        return activeConnectionPermissionService.getPermissionSet(
+                getCurrentUser(), this, Collections.<String>emptySet());
     }
 
     @Override
     public ObjectPermissionSet getUserPermissions()
             throws GuacamoleException {
-        return userPermissionService.getPermissionSet(getCurrentUser(), this, false);
+        return userPermissionService.getPermissionSet(getCurrentUser(), this,
+                Collections.<String>emptySet());
     }
 
     @Override
@@ -864,50 +870,64 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
      *     apply to this user.
      */
     public Set<String> getEffectiveUserGroups() {
-
-        // FIXME: STUB
-        return /*retrieveEffectiveIdentifiers(this, */Collections.<String>emptySet()/*)*/;
-
+        return userService.retrieveEffectiveGroups(this,
+                Collections.<String>emptySet());
     }
 
     @Override
     public Permissions getEffectivePermissions() throws GuacamoleException {
+
+        final ModeledAuthenticatedUser authenticatedUser = getCurrentUser();
+        final Set<String> effectiveGroups;
+
+        // If this user is the currently-authenticated user, include any
+        // additional effective groups declared by the authentication system
+        if (authenticatedUser.getIdentifier().equals(getIdentifier()))
+            effectiveGroups = userService.retrieveEffectiveGroups(this,
+                    authenticatedUser.getEffectiveUserGroups());
+
+        // Otherwise, just include effective groups from the database
+        else
+            effectiveGroups = getEffectiveUserGroups();
+
+        // Return a permissions object which describes all effective
+        // permissions, including any permissions inherited via user groups
         return new Permissions() {
 
             @Override
             public ObjectPermissionSet getActiveConnectionPermissions()
                     throws GuacamoleException {
-                return activeConnectionPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true);
+                return activeConnectionPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups);
             }
 
             @Override
             public ObjectPermissionSet getConnectionGroupPermissions()
                     throws GuacamoleException {
-                return connectionGroupPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true);
+                return connectionGroupPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups);
             }
 
             @Override
             public ObjectPermissionSet getConnectionPermissions()
                     throws GuacamoleException {
-                return connectionPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true);
+                return connectionPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups);
             }
 
             @Override
             public ObjectPermissionSet getSharingProfilePermissions()
                     throws GuacamoleException {
-                return sharingProfilePermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true);
+                return sharingProfilePermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups);
             }
 
             @Override
             public SystemPermissionSet getSystemPermissions()
                     throws GuacamoleException {
-                return systemPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true);
+                return systemPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups);
             }
 
             @Override
             public ObjectPermissionSet getUserPermissions()
                     throws GuacamoleException {
-                return userPermissionService.getPermissionSet(getCurrentUser(), ModeledUser.this, true);
+                return userPermissionService.getPermissionSet(authenticatedUser, ModeledUser.this, effectiveGroups);
             }
 
             @Override

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserMapper.java
index 251445b..6b51105 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserMapper.java
@@ -19,6 +19,8 @@
 
 package org.apache.guacamole.auth.jdbc.user;
 
+import java.util.Collection;
+import java.util.Set;
 import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
 import org.apache.ibatis.annotations.Param;
 
@@ -38,5 +40,25 @@ public interface UserMapper extends ModeledDirectoryObjectMapper<UserModel> {
      *     The user having the given username, or null if no such user exists.
      */
     UserModel selectOne(@Param("username") String username);
-    
+
+    /**
+     * Returns the set of all group identifiers of which the given user is a
+     * member, taking into account the given collection of known group
+     * memberships which are not necessarily defined within the database.
+     *
+     * @param user
+     *     The user whose effective groups should be returned.
+     *
+     * @param effectiveGroups
+     *     The identifiers of any known effective groups that should be taken
+     *     into account, such as those defined externally to the database.
+     *
+     * @return
+     *     The set of identifiers of all groups that the given user is a
+     *     member of, including those where membership is inherited through
+     *     membership in other groups.
+     */
+    Set<String> selectEffectiveGroupIdentifiers(@Param("user") UserModel user,
+            @Param("effectiveGroups") Collection<String> effectiveGroups);
+
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.java
index b2177bf..92501ab 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.java
@@ -113,12 +113,19 @@ public interface UserRecordMapper {
      * @param limit
      *     The maximum number of records that should be returned.
      *
+     * @param effectiveGroups
+     *     The identifiers of all groups that should be taken into account
+     *     when determining the permissions effectively granted to the user. If
+     *     no groups are given, only permissions directly granted to the user
+     *     will be used.
+     *
      * @return
      *     The results of the search performed with the given parameters.
      */
     List<ActivityRecordModel> searchReadable(@Param("user") UserModel user,
             @Param("terms") Collection<ActivityRecordSearchTerm> terms,
             @Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
-            @Param("limit") int limit);
+            @Param("limit") int limit,
+            @Param("effectiveGroups") Collection<String> effectiveGroups);
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
index 2c70e22..6d89125 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/UserService.java
@@ -26,6 +26,7 @@ import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.Set;
 import javax.servlet.http.HttpServletRequest;
 import org.apache.guacamole.net.auth.Credentials;
 import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObjectMapper;
@@ -591,11 +592,37 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
         // Otherwise only return explicitly readable history records
         else
             searchResults = userRecordMapper.searchReadable(user.getUser().getModel(),
-                    requiredContents, sortPredicates, limit);
+                    requiredContents, sortPredicates, limit, user.getEffectiveUserGroups());
 
         return getObjectInstances(searchResults);
 
     }
 
+    /**
+     * Returns the set of all group identifiers of which the given user is a
+     * member, taking into account the given collection of known group
+     * memberships which are not necessarily defined within the database.
+     * 
+     * Note that group visibility with respect to the queried user is NOT taken
+     * into account. If the user is a member of a group, the identifier of that
+     * group will be included in the returned set even if the current user lacks
+     * "READ" permission for that group.
+     *
+     * @param user
+     *     The user whose effective groups should be returned.
+     *
+     * @param effectiveGroups
+     *     The identifiers of any known effective groups that should be taken
+     *     into account, such as those defined externally to the database.
+     *
+     * @return
+     *     The set of identifiers of all groups that the given user is a
+     *     member of, including those where membership is inherited through
+     *     membership in other groups.
+     */
+    public Set<String> retrieveEffectiveGroups(ModeledUser user,
+            Collection<String> effectiveGroups) {
+        return userMapper.selectEffectiveGroupIdentifiers(user.getModel(), effectiveGroups);
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
index dd262d1..01830d7 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
@@ -23,21 +23,40 @@
 
 <mapper namespace="org.apache.guacamole.auth.jdbc.base.EntityMapper" >
 
-    <!-- Retrieves the ID of the given entity. If inheritance is enabled, the
-    IDs of the entities for all applicable user groups are retrieved, as well. -->
-    <sql id="relatedEntities">
-        <if test="!${inheritFlag}">${entityID}</if>
-        <if test="${inheritFlag}">
-            WITH RECURSIVE related_entity(entity_id) AS (
-                    VALUES (${entityID})
-                UNION
-                    SELECT guacamole_user_group.entity_id
-                    FROM related_entity
-                    JOIN guacamole_user_group_member ON related_entity.entity_id = guacamole_user_group_member.member_entity_id
-                    JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
-            )
-            SELECT entity_id FROM related_entity
-        </if>
+    <!--
+      * SQL fragment which tests whether the value of the given column matches
+      * the given entity ID. If group identifiers are provided, the IDs of the
+      * entities for all groups having those identifiers are tested, as well.
+      *
+      * @param column
+      *     The name of the column to test. This column MUST contain an entity
+      *     ID (a foreign key into the guacamole_entity table).
+      *
+      * @param entityID
+      *     The ID of the specific entity to test the column against.
+      *
+      * @param groups
+      *     A collection of group identifiers to additionally test the column
+      *     against. Though this functionality is optional, a collection must
+      *     always be given, even if that collection is empty.
+      -->
+    <sql id="isRelatedEntity">
+        (
+            ${column} = ${entityID}
+            <if test="!${groups}.isEmpty()">
+                OR ${column} IN (
+                    SELECT entity_id
+                    FROM guacamole_entity
+                    WHERE
+                        type = 'USER_GROUP'::guacamole_entity_type
+                        AND name IN
+                            <foreach collection="${groups}" item="effectiveGroup"
+                                     open="(" separator="," close=")">
+                                #{effectiveGroup,jdbcType=VARCHAR}
+                            </foreach>
+                )
+            </if>
+        )
     </sql>
 
     <!-- Insert single entity -->

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
index 94855e1..859cec5 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
@@ -68,12 +68,11 @@
         SELECT connection_id
         FROM guacamole_connection_permission
         WHERE
-            entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
     </select>
 
@@ -94,12 +93,11 @@
         WHERE
             <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer</if>
             <if test="parentIdentifier == null">parent_id IS NULL</if>
-            AND entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
     </select>
 
@@ -175,12 +173,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND guacamole_connection_permission.entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_connection_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
         GROUP BY guacamole_connection.connection_id;
 
@@ -192,12 +189,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
         SELECT
@@ -211,12 +207,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=INTEGER}::integer
             </foreach>
-            AND entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/14d10fb4/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
index b04c9ca..e8e8876 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
@@ -166,23 +166,21 @@
         <!-- Restrict to readable connections -->
         JOIN guacamole_connection_permission ON
                 guacamole_connection_history.connection_id = guacamole_connection_permission.connection_id
-            AND guacamole_connection_permission.entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_connection_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND guacamole_connection_permission.permission = 'READ'
 
         <!-- Restrict to readable users -->
         JOIN guacamole_user_permission ON
                 guacamole_connection_history.user_id = guacamole_user_permission.affected_user_id
-            AND guacamole_user_permission.entity_id IN (
-                <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.relatedEntities">
-                    <property name="inheritFlag" value="true"/>
-                    <property name="entityID"    value="#{user.entityID,jdbcType=INTEGER}"/>
-                </include>
-            )
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND guacamole_user_permission.permission = 'READ'
 
         <!-- Search terms -->


[14/38] guacamole-client git commit: GUACAMOLE-220: Update MySQL mapping with respect to user group support.

Posted by vn...@apache.org.
GUACAMOLE-220: Update MySQL mapping with respect to user group support.


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

Branch: refs/heads/master
Commit: 204b6a4b2478eccec7e502fef517c80f87d146c9
Parents: 1d0fcc1
Author: Michael Jumper <mj...@apache.org>
Authored: Sat Sep 8 11:36:54 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:52 2018 -0700

----------------------------------------------------------------------
 .../guacamole/auth/jdbc/base/EntityMapper.xml   | 123 ++++++++++
 .../auth/jdbc/connection/ConnectionMapper.xml   |  30 ++-
 .../jdbc/connection/ConnectionRecordMapper.xml  |  22 +-
 .../connectiongroup/ConnectionGroupMapper.xml   |  36 ++-
 .../ConnectionGroupPermissionMapper.xml         |  44 ++--
 .../permission/ConnectionPermissionMapper.xml   |  44 ++--
 .../SharingProfilePermissionMapper.xml          |  46 ++--
 .../jdbc/permission/SystemPermissionMapper.xml  |  40 ++--
 .../permission/UserGroupPermissionMapper.xml    | 149 ++++++++++++
 .../jdbc/permission/UserPermissionMapper.xml    |  85 ++++---
 .../sharingprofile/SharingProfileMapper.xml     |  18 +-
 .../auth/jdbc/user/PasswordRecordMapper.xml     |   3 +-
 .../guacamole/auth/jdbc/user/UserMapper.xml     |  82 +++++--
 .../jdbc/user/UserParentUserGroupMapper.xml     |  96 ++++++++
 .../auth/jdbc/user/UserRecordMapper.xml         |  29 ++-
 .../auth/jdbc/usergroup/UserGroupMapper.xml     | 229 +++++++++++++++++++
 .../UserGroupMemberUserGroupMapper.xml          |  93 ++++++++
 .../usergroup/UserGroupMemberUserMapper.xml     |  93 ++++++++
 .../UserGroupParentUserGroupMapper.xml          |  96 ++++++++
 19 files changed, 1205 insertions(+), 153 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
new file mode 100644
index 0000000..eb7a771
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.base.EntityMapper" >
+
+    <!--
+      * SQL fragment which tests whether the value of the given column matches
+      * the given entity ID. If group identifiers are provided, the IDs of the
+      * entities for all groups having those identifiers are tested, as well.
+      * Disabled groups are ignored.
+      *
+      * @param column
+      *     The name of the column to test. This column MUST contain an entity
+      *     ID (a foreign key into the guacamole_entity table).
+      *
+      * @param entityID
+      *     The ID of the specific entity to test the column against.
+      *
+      * @param groups
+      *     A collection of group identifiers to additionally test the column
+      *     against. Though this functionality is optional, a collection must
+      *     always be given, even if that collection is empty.
+      -->
+    <sql id="isRelatedEntity">
+        (
+            ${column} = ${entityID}
+            <if test="!${groups}.isEmpty()">
+                OR ${column} IN (
+                    SELECT guacamole_entity.entity_id
+                    FROM guacamole_entity
+                    JOIN guacamole_user_group ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+                    WHERE
+                        type = 'USER_GROUP'
+                        AND name IN
+                            <foreach collection="${groups}" item="effectiveGroup"
+                                     open="(" separator="," close=")">
+                                #{effectiveGroup,jdbcType=VARCHAR}
+                            </foreach>
+                        AND disabled = false
+                )
+            </if>
+        )
+    </sql>
+
+    <!-- Select names of all effective groups (including inherited) -->
+    <select id="selectEffectiveGroupIdentifiers" resultType="string">
+
+        WITH RECURSIVE related_entity(entity_id) AS (
+                SELECT
+                    guacamole_user_group.entity_id
+                FROM guacamole_user_group
+                JOIN guacamole_user_group_member ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
+                WHERE
+                    guacamole_user_group_member.member_entity_id = #{entity.entityID}
+                    AND guacamole_user_group.disabled = false
+            <if test="!effectiveGroups.isEmpty()">
+                UNION
+                    SELECT
+                        guacamole_entity.entity_id
+                    FROM guacamole_entity
+                    JOIN guacamole_user_group ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+                    WHERE
+                        type = 'USER_GROUP'
+                        AND name IN
+                            <foreach collection="effectiveGroups" item="effectiveGroup"
+                                     open="(" separator="," close=")">
+                                #{effectiveGroup,jdbcType=VARCHAR}
+                            </foreach>
+                        AND guacamole_user_group.disabled = false
+            </if>
+            UNION
+                SELECT
+                    guacamole_user_group.entity_id
+                FROM related_entity
+                JOIN guacamole_user_group_member ON related_entity.entity_id = guacamole_user_group_member.member_entity_id
+                JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
+                WHERE
+                    guacamole_user_group.disabled = false
+        )
+        SELECT name
+        FROM related_entity
+        JOIN guacamole_entity ON related_entity.entity_id = guacamole_entity.entity_id
+        WHERE
+            guacamole_entity.type = 'USER_GROUP';
+
+    </select>
+
+    <!-- Insert single entity -->
+    <insert id="insert" useGeneratedKeys="true" keyProperty="entity.entityID"
+            parameterType="org.apache.guacamole.auth.jdbc.base.EntityModel">
+
+        INSERT INTO guacamole_entity (
+            name,
+            type
+        )
+        VALUES (
+            #{entity.identifier,jdbcType=VARCHAR},
+            #{entity.entityType,jdbcType=VARCHAR}
+        )
+
+    </insert>
+
+</mapper>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
index e5fd2f0..391e90d 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml
@@ -68,7 +68,11 @@
         SELECT connection_id
         FROM guacamole_connection_permission
         WHERE
-            user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
     </select>
 
@@ -89,7 +93,11 @@
         WHERE
             <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=VARCHAR}</if>
             <if test="parentIdentifier == null">parent_id IS NULL</if>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
     </select>
 
@@ -165,7 +173,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
-            AND guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_connection_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
         GROUP BY guacamole_connection.connection_id;
 
@@ -177,7 +189,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
         SELECT
@@ -191,7 +207,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
index 287ca02..d74d4c4 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml
@@ -79,7 +79,10 @@
             #{record.sharingProfileIdentifier,jdbcType=VARCHAR},
             #{record.sharingProfileName,jdbcType=VARCHAR},
             (SELECT user_id FROM guacamole_user
-             WHERE username = #{record.username,jdbcType=VARCHAR}),
+             JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
+             WHERE
+                   guacamole_entity.name = #{record.username,jdbcType=VARCHAR}
+               AND guacamole_entity.type = 'USER'),
             #{record.username,jdbcType=VARCHAR},
             #{record.startDate,jdbcType=TIMESTAMP},
             #{record.endDate,jdbcType=TIMESTAMP}
@@ -165,13 +168,21 @@
         <!-- Restrict to readable connections -->
         JOIN guacamole_connection_permission ON
                 guacamole_connection_history.connection_id = guacamole_connection_permission.connection_id
-            AND guacamole_connection_permission.user_id    = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_connection_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND guacamole_connection_permission.permission = 'READ'
 
         <!-- Restrict to readable users -->
         JOIN guacamole_user_permission ON
                 guacamole_connection_history.user_id = guacamole_user_permission.affected_user_id
-            AND guacamole_user_permission.user_id    = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND guacamole_user_permission.permission = 'READ'
 
         <!-- Search terms -->
@@ -182,7 +193,10 @@
                 guacamole_connection_history.user_id IN (
                     SELECT user_id
                     FROM guacamole_user
-                    WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
+                    JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
+                    WHERE
+                            POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
+                        AND guacamole_entity.type = 'USER'
                 )
 
                 OR guacamole_connection_history.connection_id IN (

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
index e02a046..9addd3c 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml
@@ -69,7 +69,11 @@
         SELECT connection_group_id
         FROM guacamole_connection_group_permission
         WHERE
-            user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
     </select>
 
@@ -90,7 +94,11 @@
         WHERE
             <if test="parentIdentifier != null">parent_id = #{parentIdentifier,jdbcType=VARCHAR}</if>
             <if test="parentIdentifier == null">parent_id IS NULL</if>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
     </select>
 
@@ -161,7 +169,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
         SELECT parent_id, guacamole_connection_group.connection_group_id
@@ -172,7 +184,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
         SELECT parent_id, guacamole_connection.connection_id
@@ -183,7 +199,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
         SELECT
@@ -197,7 +217,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
index 972a71d..adb9618 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml
@@ -25,24 +25,26 @@
 
     <!-- Result mapper for connection permissions -->
     <resultMap id="ConnectionGroupPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
-        <result column="user_id"             property="userID"           jdbcType="INTEGER"/>
-        <result column="username"            property="username"         jdbcType="VARCHAR"/>
+        <result column="entity_id"           property="entityID"         jdbcType="INTEGER"/>
         <result column="permission"          property="type"             jdbcType="VARCHAR"
                 javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
         <result column="connection_group_id" property="objectIdentifier" jdbcType="INTEGER"/>
     </resultMap>
 
-    <!-- Select all permissions for a given user -->
+    <!-- Select all permissions for a given entity -->
     <select id="select" resultMap="ConnectionGroupPermissionResultMap">
 
         SELECT
-            guacamole_connection_group_permission.user_id,
-            username,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             connection_group_id
         FROM guacamole_connection_group_permission
-        JOIN guacamole_user ON guacamole_connection_group_permission.user_id = guacamole_user.user_id
-        WHERE guacamole_connection_group_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
 
     </select>
 
@@ -50,26 +52,32 @@
     <select id="selectOne" resultMap="ConnectionGroupPermissionResultMap">
 
         SELECT
-            guacamole_connection_group_permission.user_id,
-            username,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             connection_group_id
         FROM guacamole_connection_group_permission
-        JOIN guacamole_user ON guacamole_connection_group_permission.user_id = guacamole_user.user_id
         WHERE
-            guacamole_connection_group_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = #{type,jdbcType=VARCHAR}
             AND connection_group_id = #{identifier,jdbcType=VARCHAR}
 
     </select>
 
-    <!-- Select identifiers accessible by the given user for the given permissions -->
+    <!-- Select identifiers accessible by the given entity for the given permissions -->
     <select id="selectAccessibleIdentifiers" resultType="string">
 
         SELECT DISTINCT connection_group_id 
         FROM guacamole_connection_group_permission
         WHERE
-            user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND connection_group_id IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">
@@ -87,10 +95,10 @@
     <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         DELETE FROM guacamole_connection_group_permission
-        WHERE (user_id, permission, connection_group_id) IN
+        WHERE (entity_id, permission, connection_group_id) IN
             <foreach collection="permissions" item="permission"
                      open="(" separator="," close=")">
-                (#{permission.userID,jdbcType=INTEGER},
+                (#{permission.entityID,jdbcType=INTEGER},
                  #{permission.type,jdbcType=VARCHAR},
                  #{permission.objectIdentifier,jdbcType=VARCHAR})
             </foreach>
@@ -101,17 +109,17 @@
     <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         INSERT IGNORE INTO guacamole_connection_group_permission (
-            user_id,
+            entity_id,
             permission,
             connection_group_id
         )
         VALUES
             <foreach collection="permissions" item="permission" separator=",">
-                (#{permission.userID,jdbcType=INTEGER},
+                (#{permission.entityID,jdbcType=INTEGER},
                  #{permission.type,jdbcType=VARCHAR},
                  #{permission.objectIdentifier,jdbcType=VARCHAR})
             </foreach>
 
     </insert>
 
-</mapper>
\ No newline at end of file
+</mapper>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
index 985d4d5..3b8afc7 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml
@@ -25,24 +25,26 @@
 
     <!-- Result mapper for connection permissions -->
     <resultMap id="ConnectionPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
-        <result column="user_id"       property="userID"           jdbcType="INTEGER"/>
-        <result column="username"      property="username"         jdbcType="VARCHAR"/>
+        <result column="entity_id"     property="entityID"         jdbcType="INTEGER"/>
         <result column="permission"    property="type"             jdbcType="VARCHAR"
                 javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
         <result column="connection_id" property="objectIdentifier" jdbcType="INTEGER"/>
     </resultMap>
 
-    <!-- Select all permissions for a given user -->
+    <!-- Select all permissions for a given entity -->
     <select id="select" resultMap="ConnectionPermissionResultMap">
 
         SELECT
-            guacamole_connection_permission.user_id,
-            username,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             connection_id
         FROM guacamole_connection_permission
-        JOIN guacamole_user ON guacamole_connection_permission.user_id = guacamole_user.user_id
-        WHERE guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
 
     </select>
 
@@ -50,26 +52,32 @@
     <select id="selectOne" resultMap="ConnectionPermissionResultMap">
 
         SELECT
-            guacamole_connection_permission.user_id,
-            username,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             connection_id
         FROM guacamole_connection_permission
-        JOIN guacamole_user ON guacamole_connection_permission.user_id = guacamole_user.user_id
         WHERE
-            guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = #{type,jdbcType=VARCHAR}
             AND connection_id = #{identifier,jdbcType=VARCHAR}
 
     </select>
 
-    <!-- Select identifiers accessible by the given user for the given permissions -->
+    <!-- Select identifiers accessible by the given entity for the given permissions -->
     <select id="selectAccessibleIdentifiers" resultType="string">
 
         SELECT DISTINCT connection_id 
         FROM guacamole_connection_permission
         WHERE
-            user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND connection_id IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">
@@ -87,10 +95,10 @@
     <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         DELETE FROM guacamole_connection_permission
-        WHERE (user_id, permission, connection_id) IN
+        WHERE (entity_id, permission, connection_id) IN
             <foreach collection="permissions" item="permission"
                      open="(" separator="," close=")">
-                (#{permission.userID,jdbcType=INTEGER},
+                (#{permission.entityID,jdbcType=INTEGER},
                  #{permission.type,jdbcType=VARCHAR},
                  #{permission.objectIdentifier,jdbcType=VARCHAR})
             </foreach>
@@ -101,17 +109,17 @@
     <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         INSERT IGNORE INTO guacamole_connection_permission (
-            user_id,
+            entity_id,
             permission,
             connection_id
         )
         VALUES
             <foreach collection="permissions" item="permission" separator=",">
-                (#{permission.userID,jdbcType=INTEGER},
+                (#{permission.entityID,jdbcType=INTEGER},
                  #{permission.type,jdbcType=VARCHAR},
                  #{permission.objectIdentifier,jdbcType=VARCHAR})
             </foreach>
 
     </insert>
 
-</mapper>
\ No newline at end of file
+</mapper>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
index e7c1d88..a0b2872 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SharingProfilePermissionMapper.xml
@@ -23,26 +23,28 @@
 
 <mapper namespace="org.apache.guacamole.auth.jdbc.permission.SharingProfilePermissionMapper">
 
-    <!-- Result mapper for sharig profile permissions -->
+    <!-- Result mapper for sharing profile permissions -->
     <resultMap id="SharingProfilePermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
-        <result column="user_id"            property="userID"           jdbcType="INTEGER"/>
-        <result column="username"           property="username"         jdbcType="VARCHAR"/>
+        <result column="entity_id"          property="entityID"         jdbcType="INTEGER"/>
         <result column="permission"         property="type"             jdbcType="VARCHAR"
                 javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
         <result column="sharing_profile_id" property="objectIdentifier" jdbcType="INTEGER"/>
     </resultMap>
 
-    <!-- Select all permissions for a given user -->
+    <!-- Select all permissions for a given entity -->
     <select id="select" resultMap="SharingProfilePermissionResultMap">
 
         SELECT
-            guacamole_sharing_profile_permission.user_id,
-            username,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             sharing_profile_id
         FROM guacamole_sharing_profile_permission
-        JOIN guacamole_user ON guacamole_sharing_profile_permission.user_id = guacamole_user.user_id
-        WHERE guacamole_sharing_profile_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
 
     </select>
 
@@ -50,26 +52,32 @@
     <select id="selectOne" resultMap="SharingProfilePermissionResultMap">
 
         SELECT
-            guacamole_sharing_profile_permission.user_id,
-            username,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
             sharing_profile_id
         FROM guacamole_sharing_profile_permission
-        JOIN guacamole_user ON guacamole_sharing_profile_permission.user_id = guacamole_user.user_id
         WHERE
-            guacamole_sharing_profile_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = #{type,jdbcType=VARCHAR}
             AND sharing_profile_id = #{identifier,jdbcType=VARCHAR}
 
     </select>
 
-    <!-- Select identifiers accessible by the given user for the given permissions -->
+    <!-- Select identifiers accessible by the given entity for the given permissions -->
     <select id="selectAccessibleIdentifiers" resultType="string">
 
         SELECT DISTINCT sharing_profile_id
         FROM guacamole_sharing_profile_permission
         WHERE
-            user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND sharing_profile_id IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">
@@ -87,10 +95,10 @@
     <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         DELETE FROM guacamole_sharing_profile_permission
-        WHERE (user_id, permission, sharing_profile_id) IN
+        WHERE (entity_id, permission, sharing_profile_id) IN
             <foreach collection="permissions" item="permission"
                      open="(" separator="," close=")">
-                (#{permission.userID,jdbcType=INTEGER},
+                (#{permission.entityID,jdbcType=INTEGER},
                  #{permission.type,jdbcType=VARCHAR},
                  #{permission.objectIdentifier,jdbcType=VARCHAR})
             </foreach>
@@ -101,17 +109,17 @@
     <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         INSERT IGNORE INTO guacamole_sharing_profile_permission (
-            user_id,
+            entity_id,
             permission,
             sharing_profile_id
         )
         VALUES
             <foreach collection="permissions" item="permission" separator=",">
-                (#{permission.userID,jdbcType=INTEGER},
+                (#{permission.entityID,jdbcType=INTEGER},
                  #{permission.type,jdbcType=VARCHAR},
                  #{permission.objectIdentifier,jdbcType=VARCHAR})
             </foreach>
 
     </insert>
 
-</mapper>
\ No newline at end of file
+</mapper>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
index b8573ea..703c189 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml
@@ -25,36 +25,40 @@
 
     <!-- Result mapper for system permissions -->
     <resultMap id="SystemPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
-        <result column="user_id"    property="userID"   jdbcType="INTEGER"/>
-        <result column="username"   property="username" jdbcType="VARCHAR"/>
+        <result column="entity_id"  property="entityID" jdbcType="INTEGER"/>
         <result column="permission" property="type"     jdbcType="VARCHAR"
                 javaType="org.apache.guacamole.net.auth.permission.SystemPermission$Type"/>
     </resultMap>
 
-    <!-- Select all permissions for a given user -->
+    <!-- Select all permissions for a given entity -->
     <select id="select" resultMap="SystemPermissionResultMap">
 
-        SELECT
-            guacamole_system_permission.user_id,
-            username,
+        SELECT DISTINCT
+            #{entity.entityID} AS entity_id,
             permission
         FROM guacamole_system_permission
-        JOIN guacamole_user ON guacamole_system_permission.user_id = guacamole_user.user_id
-        WHERE guacamole_system_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
 
     </select>
 
     <!-- Select the single permission matching the given criteria -->
     <select id="selectOne" resultMap="SystemPermissionResultMap">
 
-        SELECT
-            guacamole_system_permission.user_id,
-            username,
+        SELECT DISTINCT
+            #{entity.entityID} AS entity_id,
             permission
         FROM guacamole_system_permission
-        JOIN guacamole_user ON guacamole_system_permission.user_id = guacamole_user.user_id
         WHERE
-            guacamole_system_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = #{type,jdbcType=VARCHAR}
 
     </select>
@@ -63,10 +67,10 @@
     <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
 
         DELETE FROM guacamole_system_permission
-        WHERE (user_id, permission) IN
+        WHERE (entity_id, permission) IN
             <foreach collection="permissions" item="permission"
                      open="(" separator="," close=")">
-                (#{permission.userID,jdbcType=INTEGER},
+                (#{permission.entityID,jdbcType=INTEGER},
                  #{permission.type,jdbcType=VARCHAR})
             </foreach>
 
@@ -76,15 +80,15 @@
     <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.SystemPermissionModel">
 
         INSERT IGNORE INTO guacamole_system_permission (
-            user_id,
+            entity_id,
             permission
         )
         VALUES
             <foreach collection="permissions" item="permission" separator=",">
-                (#{permission.userID,jdbcType=INTEGER},
+                (#{permission.entityID,jdbcType=INTEGER},
                  #{permission.type,jdbcType=VARCHAR})
             </foreach>
 
     </insert>
 
-</mapper>
\ No newline at end of file
+</mapper>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml
new file mode 100644
index 0000000..d8af2bc
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserGroupPermissionMapper.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.permission.UserGroupPermissionMapper" >
+
+    <!-- Result mapper for user group permissions -->
+    <resultMap id="UserGroupPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
+        <result column="entity_id"         property="entityID"         jdbcType="INTEGER"/>
+        <result column="permission"        property="type"             jdbcType="VARCHAR"
+                javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
+        <result column="affected_name"     property="objectIdentifier" jdbcType="INTEGER"/>
+    </resultMap>
+
+    <!-- Select all permissions for a given entity -->
+    <select id="select" resultMap="UserGroupPermissionResultMap">
+
+        SELECT
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
+            permission,
+            affected_entity.name AS affected_name
+        FROM guacamole_user_group_permission
+        JOIN guacamole_user_group affected_group ON guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id
+        JOIN guacamole_entity affected_entity ON affected_group.entity_id = affected_entity.entity_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_group_permission.entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND affected_entity.type = 'USER_GROUP'
+
+    </select>
+
+    <!-- Select the single permission matching the given criteria -->
+    <select id="selectOne" resultMap="UserGroupPermissionResultMap">
+
+        SELECT
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
+            permission,
+            affected_entity.name AS affected_name
+        FROM guacamole_user_group_permission
+        JOIN guacamole_user_group affected_group ON guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id
+        JOIN guacamole_entity affected_entity ON affected_group.entity_id = affected_entity.entity_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_group_permission.entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND permission = #{type,jdbcType=VARCHAR}
+            AND affected_entity.name = #{identifier,jdbcType=VARCHAR}
+            AND affected_entity.type = 'USER_GROUP'
+
+    </select>
+
+    <!-- Select identifiers accessible by the given entity for the given permissions -->
+    <select id="selectAccessibleIdentifiers" resultType="string">
+
+        SELECT DISTINCT affected_entity.name
+        FROM guacamole_user_group_permission
+        JOIN guacamole_user_group affected_group ON guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id
+        JOIN guacamole_entity affected_entity ON affected_group.entity_id = affected_entity.entity_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_group_permission.entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND affected_entity.name IN
+                <foreach collection="identifiers" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+            AND permission IN
+                <foreach collection="permissions" item="permission"
+                         open="(" separator="," close=")">
+                    #{permission,jdbcType=VARCHAR}
+                </foreach>
+            AND affected_entity.type = 'USER_GROUP'
+
+    </select>
+
+    <!-- Delete all given permissions -->
+    <delete id="delete" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
+
+        DELETE FROM guacamole_user_group_permission
+        USING guacamole_user_group_permission
+        JOIN guacamole_user_group affected_group ON guacamole_user_group_permission.affected_user_group_id = affected_group.user_group_id
+        JOIN guacamole_entity affected_entity ON affected_group.entity_id = affected_entity.entity_id
+        WHERE
+            (guacamole_user_group_permission.entity_id, permission, affected_entity.name) IN
+                <foreach collection="permissions" item="permission"
+                         open="(" separator="," close=")">
+                    (#{permission.entityID,jdbcType=INTEGER},
+                     #{permission.type,jdbcType=VARCHAR},
+                     #{permission.objectIdentifier,jdbcType=VARCHAR})
+                </foreach>
+            AND affected_entity.type = 'USER_GROUP'
+
+    </delete>
+
+    <!-- Insert all given permissions -->
+    <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
+
+        INSERT IGNORE INTO guacamole_user_group_permission (
+            entity_id,
+            permission,
+            affected_user_group_id
+        )
+        SELECT DISTINCT
+            permissions.entity_id,
+            permissions.permission,
+            affected_group.user_group_id
+        FROM
+            <foreach collection="permissions" item="permission"
+                     open="(" separator="UNION ALL" close=")">
+                SELECT #{permission.entityID,jdbcType=INTEGER}         AS entity_id,
+                       #{permission.type,jdbcType=VARCHAR}             AS permission,
+                       #{permission.objectIdentifier,jdbcType=VARCHAR} AS affected_name
+            </foreach>
+        AS permissions
+        JOIN guacamole_entity affected_entity ON
+                affected_entity.name = permissions.affected_name
+            AND affected_entity.type = 'USER_GROUP'
+        JOIN guacamole_user_group affected_group ON affected_group.entity_id = affected_entity.entity_id
+
+    </insert>
+
+</mapper>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
index 3b837de..4470aa3 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/permission/UserPermissionMapper.xml
@@ -25,25 +25,29 @@
 
     <!-- Result mapper for user permissions -->
     <resultMap id="UserPermissionResultMap" type="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
-        <result column="user_id"           property="userID"           jdbcType="INTEGER"/>
-        <result column="username"          property="username"         jdbcType="VARCHAR"/>
+        <result column="entity_id"         property="entityID"         jdbcType="INTEGER"/>
         <result column="permission"        property="type"             jdbcType="VARCHAR"
                 javaType="org.apache.guacamole.net.auth.permission.ObjectPermission$Type"/>
-        <result column="affected_username" property="objectIdentifier" jdbcType="INTEGER"/>
+        <result column="affected_name"     property="objectIdentifier" jdbcType="INTEGER"/>
     </resultMap>
 
-    <!-- Select all permissions for a given user -->
+    <!-- Select all permissions for a given entity -->
     <select id="select" resultMap="UserPermissionResultMap">
 
         SELECT
-            guacamole_user_permission.user_id,
-            guacamole_user.username,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
-            affected.username AS affected_username
+            affected_entity.name AS affected_name
         FROM guacamole_user_permission
-        JOIN guacamole_user          ON guacamole_user_permission.user_id          = guacamole_user.user_id
-        JOIN guacamole_user affected ON guacamole_user_permission.affected_user_id = affected.user_id
-        WHERE guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+        JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
+        JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_permission.entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND affected_entity.type = 'USER'
 
     </select>
 
@@ -51,29 +55,38 @@
     <select id="selectOne" resultMap="UserPermissionResultMap">
 
         SELECT
-            guacamole_user_permission.user_id,
-            guacamole_user.username,
+            #{entity.entityID,jdbcType=INTEGER} AS entity_id,
             permission,
-            affected.username AS affected_username
+            affected_entity.name AS affected_name
         FROM guacamole_user_permission
-        JOIN guacamole_user          ON guacamole_user_permission.user_id          = guacamole_user.user_id
-        JOIN guacamole_user affected ON guacamole_user_permission.affected_user_id = affected.user_id
+        JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
+        JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
         WHERE
-            guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_permission.entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = #{type,jdbcType=VARCHAR}
-            AND affected.username = #{identifier,jdbcType=VARCHAR}
+            AND affected_entity.name = #{identifier,jdbcType=VARCHAR}
+            AND affected_entity.type = 'USER'
 
     </select>
 
-    <!-- Select identifiers accessible by the given user for the given permissions -->
+    <!-- Select identifiers accessible by the given entity for the given permissions -->
     <select id="selectAccessibleIdentifiers" resultType="string">
 
-        SELECT DISTINCT username
+        SELECT DISTINCT affected_entity.name
         FROM guacamole_user_permission
-        JOIN guacamole_user ON guacamole_user_permission.affected_user_id = guacamole_user.user_id
+        JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
+        JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
         WHERE
-            guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
-            AND username IN
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_permission.entity_id"/>
+                <property name="entityID" value="#{entity.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND affected_entity.name IN
                 <foreach collection="identifiers" item="identifier"
                          open="(" separator="," close=")">
                     #{identifier,jdbcType=VARCHAR}
@@ -83,6 +96,7 @@
                          open="(" separator="," close=")">
                     #{permission,jdbcType=VARCHAR}
                 </foreach>
+            AND affected_entity.type = 'USER'
 
     </select>
 
@@ -91,15 +105,17 @@
 
         DELETE FROM guacamole_user_permission
         USING guacamole_user_permission
-        JOIN guacamole_user affected ON guacamole_user_permission.affected_user_id = affected.user_id
+        JOIN guacamole_user affected_user ON guacamole_user_permission.affected_user_id = affected_user.user_id
+        JOIN guacamole_entity affected_entity ON affected_user.entity_id = affected_entity.entity_id
         WHERE
-            (guacamole_user_permission.user_id, permission, affected.username) IN
+            (guacamole_user_permission.entity_id, permission, affected_entity.name) IN
                 <foreach collection="permissions" item="permission"
                          open="(" separator="," close=")">
-                    (#{permission.userID,jdbcType=INTEGER},
+                    (#{permission.entityID,jdbcType=INTEGER},
                      #{permission.type,jdbcType=VARCHAR},
                      #{permission.objectIdentifier,jdbcType=VARCHAR})
                 </foreach>
+            AND affected_entity.type = 'USER'
 
     </delete>
 
@@ -107,20 +123,27 @@
     <insert id="insert" parameterType="org.apache.guacamole.auth.jdbc.permission.ObjectPermissionModel">
 
         INSERT IGNORE INTO guacamole_user_permission (
-            user_id,
+            entity_id,
             permission,
             affected_user_id
         )
-        SELECT permissions.user_id, permissions.permission, guacamole_user.user_id FROM
+        SELECT DISTINCT
+            permissions.entity_id,
+            permissions.permission,
+            affected_user.user_id
+        FROM
             <foreach collection="permissions" item="permission"
                      open="(" separator="UNION ALL" close=")">
-                SELECT #{permission.userID,jdbcType=INTEGER}           AS user_id,
+                SELECT #{permission.entityID,jdbcType=INTEGER}         AS entity_id,
                        #{permission.type,jdbcType=VARCHAR}             AS permission,
-                       #{permission.objectIdentifier,jdbcType=VARCHAR} AS username
+                       #{permission.objectIdentifier,jdbcType=VARCHAR} AS affected_name
             </foreach>
         AS permissions
-        JOIN guacamole_user ON guacamole_user.username = permissions.username; 
+        JOIN guacamole_entity affected_entity ON
+                affected_entity.name = permissions.affected_name
+            AND affected_entity.type = 'USER'
+        JOIN guacamole_user affected_user ON affected_user.entity_id = affected_entity.entity_id
 
     </insert>
 
-</mapper>
\ No newline at end of file
+</mapper>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
index ef89913..7ffdc3d 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml
@@ -52,7 +52,11 @@
         SELECT sharing_profile_id
         FROM guacamole_sharing_profile_permission
         WHERE
-            user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
     </select>
 
@@ -99,7 +103,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
         SELECT
@@ -113,7 +121,11 @@
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
-            AND user_id = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
     </select>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml
index be9f0b6..f3772d7 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/PasswordRecordMapper.xml
@@ -41,8 +41,9 @@
             guacamole_user_password_history.password_date
         FROM guacamole_user_password_history
         JOIN guacamole_user ON guacamole_user_password_history.user_id = guacamole_user.user_id
+        JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
         WHERE
-            guacamole_user.username = #{username,jdbcType=VARCHAR}
+            guacamole_entity.name = #{username,jdbcType=VARCHAR}
         ORDER BY
             guacamole_user_password_history.password_date DESC
         LIMIT #{maxHistorySize}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
index e183fe2..a27ff1b 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml
@@ -28,7 +28,8 @@
 
         <!-- User properties -->
         <id     column="user_id"             property="objectID"           jdbcType="INTEGER"/>
-        <result column="username"            property="identifier"         jdbcType="VARCHAR"/>
+        <result column="entity_id"           property="entityID"           jdbcType="INTEGER"/>
+        <result column="name"                property="identifier"         jdbcType="VARCHAR"/>
         <result column="password_hash"       property="passwordHash"       jdbcType="BINARY"/>
         <result column="password_salt"       property="passwordSalt"       jdbcType="BINARY"/>
         <result column="password_date"       property="passwordDate"       jdbcType="TIMESTAMP"/>
@@ -57,17 +58,24 @@
 
     <!-- Select all usernames -->
     <select id="selectIdentifiers" resultType="string">
-        SELECT username
-        FROM guacamole_user
+        SELECT name
+        FROM guacamole_entity
+        WHERE guacamole_entity.type = 'USER'
     </select>
 
     <!-- Select usernames of all readable users -->
     <select id="selectReadableIdentifiers" resultType="string">
-        SELECT username
+        SELECT guacamole_entity.name
         FROM guacamole_user
+        JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
         JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
         WHERE
-            guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND guacamole_entity.type = 'USER'
             AND permission = 'READ'
     </select>
 
@@ -77,7 +85,8 @@
 
         SELECT
             guacamole_user.user_id,
-            guacamole_user.username,
+            guacamole_entity.entity_id,
+            guacamole_entity.name,
             password_hash,
             password_salt,
             password_date,
@@ -94,13 +103,15 @@
             organizational_role,
             MAX(start_date) AS last_active
         FROM guacamole_user
+        JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
         LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
-        WHERE guacamole_user.username IN
+        WHERE guacamole_entity.name IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
-        GROUP BY guacamole_user.user_id;
+            AND guacamole_entity.type = 'USER'
+        GROUP BY guacamole_user.user_id, guacamole_entity.entity_id;
 
         SELECT
             guacamole_user_attribute.user_id,
@@ -108,11 +119,13 @@
             guacamole_user_attribute.attribute_value
         FROM guacamole_user_attribute
         JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
-        WHERE username IN
+        JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
+        WHERE guacamole_entity.name IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
-            </foreach>;
+            </foreach>
+            AND guacamole_entity.type = 'USER';
 
     </select>
 
@@ -122,7 +135,8 @@
 
         SELECT
             guacamole_user.user_id,
-            guacamole_user.username,
+            guacamole_entity.entity_id,
+            guacamole_entity.name,
             password_hash,
             password_salt,
             password_date,
@@ -139,16 +153,22 @@
             organizational_role,
             MAX(start_date) AS last_active
         FROM guacamole_user
+        JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
         JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
         LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
-        WHERE guacamole_user.username IN
+        WHERE guacamole_entity.name IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
-            AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER'
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ'
-        GROUP BY guacamole_user.user_id;
+        GROUP BY guacamole_user.user_id, guacamole_entity.entity_id;
 
         SELECT
             guacamole_user_attribute.user_id,
@@ -156,13 +176,19 @@
             guacamole_user_attribute.attribute_value
         FROM guacamole_user_attribute
         JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
+        JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
         JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
-        WHERE username IN
+        WHERE guacamole_entity.name IN
             <foreach collection="identifiers" item="identifier"
                      open="(" separator="," close=")">
                 #{identifier,jdbcType=VARCHAR}
             </foreach>
-            AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER'
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND permission = 'READ';
 
     </select>
@@ -173,7 +199,8 @@
 
         SELECT
             guacamole_user.user_id,
-            guacamole_user.username,
+            guacamole_entity.entity_id,
+            guacamole_entity.name,
             password_hash,
             password_salt,
             password_date,
@@ -190,10 +217,12 @@
             organizational_role,
             MAX(start_date) AS last_active
         FROM guacamole_user
+        JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
         LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
         WHERE
-            guacamole_user.username = #{username,jdbcType=VARCHAR}
-        GROUP BY guacamole_user.user_id;
+            guacamole_entity.name = #{username,jdbcType=VARCHAR}
+            AND guacamole_entity.type = 'USER'
+        GROUP BY guacamole_user.user_id, guacamole_entity.entity_id;
 
         SELECT
             guacamole_user_attribute.user_id,
@@ -201,14 +230,19 @@
             guacamole_user_attribute.attribute_value
         FROM guacamole_user_attribute
         JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
-        WHERE username = #{username,jdbcType=VARCHAR};
+        JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
+        WHERE
+            guacamole_entity.name = #{username,jdbcType=VARCHAR}
+            AND guacamole_entity.type = 'USER'
 
     </select>
 
     <!-- Delete single user by username -->
     <delete id="delete">
-        DELETE FROM guacamole_user
-        WHERE username = #{identifier,jdbcType=VARCHAR}
+        DELETE FROM guacamole_entity
+        WHERE
+            name = #{identifier,jdbcType=VARCHAR}
+            AND type = 'USER'
     </delete>
 
     <!-- Insert single user -->
@@ -216,7 +250,7 @@
             parameterType="org.apache.guacamole.auth.jdbc.user.UserModel">
 
         INSERT INTO guacamole_user (
-            username,
+            entity_id,
             password_hash,
             password_salt,
             password_date,
@@ -233,7 +267,7 @@
             organizational_role
         )
         VALUES (
-            #{object.identifier,jdbcType=VARCHAR},
+            #{object.entityID,jdbcType=VARCHAR},
             #{object.passwordHash,jdbcType=BINARY},
             #{object.passwordSalt,jdbcType=BINARY},
             #{object.passwordDate,jdbcType=TIMESTAMP},

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml
new file mode 100644
index 0000000..1b0ec4e
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserParentUserGroupMapper.xml
@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
+
+<!--
+    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.
+-->
+
+<mapper namespace="org.apache.guacamole.auth.jdbc.user.UserParentUserGroupMapper" >
+
+    <!-- Select the names of all parent user groups -->
+    <select id="selectChildIdentifiers" resultType="string">
+        SELECT name
+        FROM guacamole_user_group_member
+        JOIN guacamole_user_group ON guacamole_user_group_member.user_group_id = guacamole_user_group.user_group_id
+        JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group.entity_id
+        WHERE
+            guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER_GROUP'
+    </select>
+
+    <!-- Select the names of all readable parent user groups -->
+    <select id="selectReadableChildIdentifiers" resultType="string">
+        SELECT guacamole_entity.name
+        FROM guacamole_user_group_member
+        JOIN guacamole_user_group ON guacamole_user_group_member.user_group_id = guacamole_user_group.user_group_id
+        JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group.entity_id
+        JOIN guacamole_user_group_permission ON affected_user_group_id = guacamole_user_group.user_group_id
+        WHERE
+            <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_group_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
+            AND guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER_GROUP'
+            AND permission = 'READ'
+    </select>
+
+    <!-- Delete parent groups by name -->
+    <delete id="delete">
+        DELETE FROM guacamole_user_group_member
+        USING guacamole_user_group_member
+        JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
+        JOIN guacamole_entity ON guacamole_entity.entity_id = guacamole_user_group.entity_id
+        WHERE
+            member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            AND guacamole_entity.type = 'USER_GROUP'
+            AND guacamole_entity.name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+    </delete>
+
+    <!-- Insert parent groups by name -->
+    <insert id="insert">
+        INSERT INTO guacamole_user_group_member (
+            user_group_id,
+            member_entity_id
+        )
+        SELECT DISTINCT
+            guacamole_user_group.user_group_id,
+            #{parent.entityID,jdbcType=INTEGER}
+        FROM guacamole_user_group
+        JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+        WHERE
+            guacamole_entity.name IN
+                <foreach collection="children" item="identifier"
+                         open="(" separator="," close=")">
+                    #{identifier,jdbcType=VARCHAR}
+                </foreach>
+            AND guacamole_entity.type = 'USER_GROUP'
+            AND guacamole_user_group.user_group_id NOT IN (
+                SELECT guacamole_user_group_member.user_group_id
+                FROM guacamole_user_group_member
+                WHERE guacamole_user_group_member.member_entity_id = #{parent.entityID,jdbcType=INTEGER}
+            )
+    </insert>
+
+</mapper>

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/204b6a4b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
index bbae03b..d9c02ef 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserRecordMapper.xml
@@ -44,8 +44,9 @@
             guacamole_user_history.end_date
         FROM guacamole_user_history
         JOIN guacamole_user ON guacamole_user_history.user_id = guacamole_user.user_id
+        JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
         WHERE
-            guacamole_user.username = #{username,jdbcType=VARCHAR}
+            guacamole_entity.name = #{username,jdbcType=VARCHAR}
         ORDER BY
             guacamole_user_history.start_date DESC,
             guacamole_user_history.end_date DESC
@@ -66,7 +67,10 @@
         VALUES (
             #{record.remoteHost,jdbcType=VARCHAR},
             (SELECT user_id FROM guacamole_user
-             WHERE username = #{record.username,jdbcType=VARCHAR}),
+             JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
+             WHERE
+                   guacamole_entity.name = #{record.username,jdbcType=VARCHAR}
+               AND guacamole_entity.type = 'USER'),
             #{record.username,jdbcType=VARCHAR},
             #{record.startDate,jdbcType=TIMESTAMP},
             #{record.endDate,jdbcType=TIMESTAMP}
@@ -79,7 +83,10 @@
         UPDATE guacamole_user_history
         SET remote_host = #{record.remoteHost,jdbcType=VARCHAR},
             user_id     = (SELECT user_id FROM guacamole_user
-                           WHERE username = #{record.username,jdbcType=VARCHAR}),
+                           JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
+                           WHERE
+                                   guacamole_entity.name = #{record.username,jdbcType=VARCHAR}
+                               AND guacamole_entity.type = 'USER'),
             username    = #{record.username,jdbcType=VARCHAR},
             start_date  = #{record.startDate,jdbcType=TIMESTAMP},
             end_date    = #{record.endDate,jdbcType=TIMESTAMP}
@@ -105,7 +112,10 @@
                 guacamole_user_history.user_id IN (
                     SELECT user_id
                     FROM guacamole_user
-                    WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
+                    JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
+                    WHERE
+                            POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
+                        AND guacamole_entity.type = 'USER'),
                 )
 
                 <if test="term.startDate != null and term.endDate != null">
@@ -146,7 +156,11 @@
         <!-- Restrict to readable users -->
         JOIN guacamole_user_permission ON
                 guacamole_user_history.user_id       = guacamole_user_permission.affected_user_id
-            AND guacamole_user_permission.user_id    = #{user.objectID,jdbcType=INTEGER}
+            AND <include refid="org.apache.guacamole.auth.jdbc.base.EntityMapper.isRelatedEntity">
+                <property name="column"   value="guacamole_user_permission.entity_id"/>
+                <property name="entityID" value="#{user.entityID,jdbcType=INTEGER}"/>
+                <property name="groups"   value="effectiveGroups"/>
+            </include>
             AND guacamole_user_permission.permission = 'READ'
 
         <!-- Search terms -->
@@ -157,7 +171,10 @@
                 guacamole_user_history.user_id IN (
                     SELECT user_id
                     FROM guacamole_user
-                    WHERE POSITION(#{term.term,jdbcType=VARCHAR} IN username) > 0
+                    JOIN guacamole_entity ON guacamole_user.entity_id = guacamole_entity.entity_id
+                    WHERE
+                            POSITION(#{term.term,jdbcType=VARCHAR} IN guacamole_entity.name) > 0
+                        AND guacamole_entity.type = 'USER'
                 )
 
                 <if test="term.startDate != null and term.endDate != null">


[34/38] guacamole-client git commit: GUACAMOLE-220: Correct documentation of update script.

Posted by vn...@apache.org.
GUACAMOLE-220: Correct documentation of update script.

The UNIQUE constraint is being added once the column is expected to be
unique, not necessarily because it should safely point to entries of a
particular table.

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

Branch: refs/heads/master
Commit: bb6e8bc1c74e5aab7978fe8c2ca70c84a929f924
Parents: 7521cdc
Author: Michael Jumper <mj...@apache.org>
Authored: Thu Sep 27 20:15:23 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Thu Sep 27 20:15:23 2018 -0700

----------------------------------------------------------------------
 .../guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.0.0.sql | 2 +-
 .../schema/upgrade/upgrade-pre-1.0.0.sql                           | 2 +-
 .../schema/upgrade/upgrade-pre-1.0.0.sql                           | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/bb6e8bc1/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.0.0.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.0.0.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.0.0.sql
index 8332d7f..0fccb61 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.0.0.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.0.0.sql
@@ -145,7 +145,7 @@ UPDATE guacamole_user SET entity_id = (
 -- The entity_id column should now be safely non-NULL
 ALTER TABLE guacamole_user MODIFY entity_id int(11) NOT NULL;
 
--- The entity_id column should now safely point to guacamole_entity entries
+-- The entity_id column should now be unique for each user
 ALTER TABLE guacamole_user
     ADD CONSTRAINT guacamole_user_single_entity
     UNIQUE (entity_id);

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/bb6e8bc1/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.0.0.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.0.0.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.0.0.sql
index dd341dc..83dfa86 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.0.0.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.0.0.sql
@@ -155,7 +155,7 @@ UPDATE guacamole_user SET entity_id = (
 ALTER TABLE guacamole_user
     ALTER COLUMN entity_id SET NOT NULL;
 
--- The entity_id column should now safely point to guacamole_entity entries
+-- The entity_id column should now be unique for each user
 ALTER TABLE guacamole_user
     ADD CONSTRAINT guacamole_user_single_entity
     UNIQUE (entity_id);

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/bb6e8bc1/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.0.0.sql
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.0.0.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.0.0.sql
index 6e9133a..7b4fc88 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.0.0.sql
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.0.0.sql
@@ -202,7 +202,7 @@ GO
 ALTER TABLE [guacamole_user]
     ALTER COLUMN [entity_id] [int] NOT NULL;
 
--- The entity_id column should now safely point to guacamole_entity entries
+-- The entity_id column should now be unique for each user
 ALTER TABLE [guacamole_user]
     ADD CONSTRAINT [AK_guacamole_user_single_entity]
     UNIQUE ([entity_id]);


[29/38] guacamole-client git commit: GUACAMOLE-220: Correct user vs. entity wording in documentation.

Posted by vn...@apache.org.
GUACAMOLE-220: Correct user vs. entity wording in documentation.

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

Branch: refs/heads/master
Commit: 4a5f271702c0777849b615848b168ea8d0a36168
Parents: 8399b25
Author: Michael Jumper <mj...@apache.org>
Authored: Thu Sep 27 19:45:30 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Thu Sep 27 19:45:30 2018 -0700

----------------------------------------------------------------------
 .../auth/jdbc/permission/PermissionService.java       |  2 +-
 .../auth/jdbc/permission/SystemPermissionService.java | 14 +++++++-------
 2 files changed, 8 insertions(+), 8 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/4a5f2717/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java
index 5d88887..a48157e 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/PermissionService.java
@@ -136,7 +136,7 @@ public interface PermissionService<PermissionSetType extends PermissionSet<Permi
      *     The permissions to delete.
      *
      * @throws GuacamoleException
-     *     If the entity lacks permission to delete the permissions, or an error
+     *     If the user lacks permission to delete the permissions, or an error
      *     occurs while deleting the permissions.
      */
     void deletePermissions(ModeledAuthenticatedUser user,

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/4a5f2717/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
index c94a260..5e5a43b 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/permission/SystemPermissionService.java
@@ -68,7 +68,7 @@ public class SystemPermissionService
 
         SystemPermissionModel model = new SystemPermissionModel();
 
-        // Populate model object with data from user and permission
+        // Populate model object with data from entity and permission
         model.setEntityID(targetEntity.getModel().getEntityID());
         model.setType(permission.getType());
 
@@ -81,7 +81,7 @@ public class SystemPermissionService
             ModeledPermissions<? extends EntityModel> targetEntity,
             Set<String> effectiveGroups) throws GuacamoleException {
 
-        // Create permission set for requested user
+        // Create permission set for requested entity
         SystemPermissionSet permissionSet = systemPermissionSetProvider.get();
         permissionSet.init(user, targetEntity, effectiveGroups);
 
@@ -144,13 +144,13 @@ public class SystemPermissionService
      *
      * @param effectiveGroups
      *     The identifiers of all groups that should be taken into account
-     *     when determining the permissions effectively granted to the user. If
-     *     no groups are given, only permissions directly granted to the user
-     *     will be used.
+     *     when determining the permissions effectively granted to the entity.
+     *     If no groups are given, only permissions directly granted to the
+     *     entity will be used.
      *
      * @return
      *     true if permission of the given type has been granted to the given
-     *     user, false otherwise.
+     *     entity, false otherwise.
      *
      * @throws GuacamoleException
      *     If an error occurs while retrieving the requested permission.
@@ -164,7 +164,7 @@ public class SystemPermissionService
         if (canReadPermissions(user, targetEntity))
             return getPermissionMapper().selectOne(targetEntity.getModel(), type, effectiveGroups) != null;
 
-        // User cannot read this user's permissions
+        // User cannot read this entity's permissions
         throw new GuacamoleSecurityException("Permission denied.");
         
     }


[19/38] guacamole-client git commit: GUACAMOLE-220: Take group "disabled" flag into account when determining effective groups. Do not inherit from nor apply disabled groups.

Posted by vn...@apache.org.
GUACAMOLE-220: Take group "disabled" flag into account when determining effective groups. Do not inherit from nor apply disabled groups.

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

Branch: refs/heads/master
Commit: a39d86379730f5a163e8a2c96ac5f9ecaeefa4ec
Parents: c5c2984
Author: Michael Jumper <mj...@apache.org>
Authored: Sun Apr 8 00:27:16 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:52 2018 -0700

----------------------------------------------------------------------
 .../org/apache/guacamole/auth/jdbc/base/EntityMapper.xml  | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/a39d8637/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
index b2ae26c..ca779a2 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
@@ -27,6 +27,7 @@
       * SQL fragment which tests whether the value of the given column matches
       * the given entity ID. If group identifiers are provided, the IDs of the
       * entities for all groups having those identifiers are tested, as well.
+      * Disabled groups are ignored.
       *
       * @param column
       *     The name of the column to test. This column MUST contain an entity
@@ -45,8 +46,9 @@
             ${column} = ${entityID}
             <if test="!${groups}.isEmpty()">
                 OR ${column} IN (
-                    SELECT entity_id
+                    SELECT guacamole_entity.entity_id
                     FROM guacamole_entity
+                    JOIN guacamole_user_group ON guacamole_user_group.entity_id = guacamole_entity.entity_id
                     WHERE
                         type = 'USER_GROUP'::guacamole_entity_type
                         AND name IN
@@ -54,6 +56,7 @@
                                      open="(" separator="," close=")">
                                 #{effectiveGroup,jdbcType=VARCHAR}
                             </foreach>
+                        AND disabled = false
                 )
             </if>
         )
@@ -69,11 +72,13 @@
                 JOIN guacamole_user_group_member ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
                 WHERE
                     guacamole_user_group_member.member_entity_id = #{entity.entityID}
+                    AND guacamole_user_group.disabled = false
             <if test="!effectiveGroups.isEmpty()">
                 UNION
                     SELECT
                         guacamole_entity.entity_id
                     FROM guacamole_entity
+                    JOIN guacamole_user_group ON guacamole_user_group.entity_id = guacamole_entity.entity_id
                     WHERE
                         type = 'USER_GROUP'::guacamole_entity_type
                         AND name IN
@@ -81,6 +86,7 @@
                                      open="(" separator="," close=")">
                                 #{effectiveGroup,jdbcType=VARCHAR}
                             </foreach>
+                        AND guacamole_user_group.disabled = false
             </if>
             UNION
                 SELECT
@@ -88,6 +94,8 @@
                 FROM related_entity
                 JOIN guacamole_user_group_member ON related_entity.entity_id = guacamole_user_group_member.member_entity_id
                 JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
+                WHERE
+                    guacamole_user_group.disabled = false
         )
         SELECT name
         FROM related_entity


[30/38] guacamole-client git commit: GUACAMOLE-220: Remove unnecessary ModeledUserGroup constructor (equivalent to default constructor).

Posted by vn...@apache.org.
GUACAMOLE-220: Remove unnecessary ModeledUserGroup constructor (equivalent to default constructor).

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

Branch: refs/heads/master
Commit: fedccebb93df1c2c9eecaa1338e9975def1b9048
Parents: 4a5f271
Author: Michael Jumper <mj...@apache.org>
Authored: Thu Sep 27 20:03:35 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Thu Sep 27 20:03:35 2018 -0700

----------------------------------------------------------------------
 .../apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java | 6 ------
 1 file changed, 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/fedccebb/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
index 914a292..b31b61e 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/usergroup/ModeledUserGroup.java
@@ -123,12 +123,6 @@ public class ModeledUserGroup extends ModeledPermissions<UserGroupModel>
     }
 
     /**
-     * Creates a new, empty ModeledUserGroup.
-     */
-    public ModeledUserGroup() {
-    }
-
-    /**
      * Stores all restricted (privileged) attributes within the given Map,
      * pulling the values of those attributes from the underlying user group
      * model. If no value is yet defined for an attribute, that attribute will


[28/38] guacamole-client git commit: GUACAMOLE-220: Dynamically detect whether the MariaDB / MySQL server supports recursive CTEs.

Posted by vn...@apache.org.
GUACAMOLE-220: Dynamically detect whether the MariaDB / MySQL server supports recursive CTEs.


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

Branch: refs/heads/master
Commit: dec7b3c340dfe1ccd76292fc8e99ae4ec42dcc03
Parents: 204b6a4
Author: Michael Jumper <mj...@apache.org>
Authored: Sat Sep 8 18:11:36 2018 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Sep 19 23:56:53 2018 -0700

----------------------------------------------------------------------
 .../guacamole/auth/jdbc/JDBCEnvironment.java    |   6 +-
 .../guacamole/auth/jdbc/base/EntityMapper.java  |  11 +-
 .../guacamole/auth/jdbc/base/EntityService.java |  16 +-
 .../guacamole/auth/mysql/MySQLEnvironment.java  |  52 ++++++-
 .../guacamole/auth/mysql/MySQLVersion.java      | 153 +++++++++++++++++++
 .../guacamole/auth/jdbc/base/EntityMapper.xml   |  99 ++++++++----
 .../auth/postgresql/PostgreSQLEnvironment.java  |   3 +-
 .../auth/sqlserver/SQLServerEnvironment.java    |   3 +-
 8 files changed, 300 insertions(+), 43 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/dec7b3c3/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java
index 93cc7f7..9158afb 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/JDBCEnvironment.java
@@ -22,6 +22,7 @@ package org.apache.guacamole.auth.jdbc;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.environment.LocalEnvironment;
 import org.apache.guacamole.auth.jdbc.security.PasswordPolicy;
+import org.apache.ibatis.session.SqlSession;
 
 /**
  * A JDBC-specific implementation of Environment that defines generic properties
@@ -143,9 +144,12 @@ public abstract class JDBCEnvironment extends LocalEnvironment {
      * not supported, queries that are intended to be recursive may need to be
      * invoked multiple times to retrieve the same data.
      *
+     * @param session
+     *     The SqlSession provided by MyBatis for the current transaction.
+     *
      * @return
      *     true if the database supports recursive queries, false otherwise.
      */
-    public abstract boolean isRecursiveQuerySupported();
+    public abstract boolean isRecursiveQuerySupported(SqlSession session);
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/dec7b3c3/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java
index 53b0290..dbe7cb4 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityMapper.java
@@ -60,12 +60,21 @@ public interface EntityMapper {
      *     The identifiers of any known effective groups that should be taken
      *     into account, such as those defined externally to the database.
      *
+     * @param recursive
+     *     Whether the query should leverage database engine features to return
+     *     absolutely all effective groups, including those inherited through
+     *     group membership. If false, this query will return only one level of
+     *     depth and may need to be executed multiple times. If it is known
+     *     that the database engine in question will always support (or always
+     *     not support) recursive queries, this parameter may be ignored.
+     *
      * @return
      *     The set of identifiers of all groups that the given entity is a
      *     member of, including those where membership is inherited through
      *     membership in other groups.
      */
     Set<String> selectEffectiveGroupIdentifiers(@Param("entity") EntityModel entity,
-            @Param("effectiveGroups") Collection<String> effectiveGroups);
+            @Param("effectiveGroups") Collection<String> effectiveGroups,
+            @Param("recursive") boolean recursive);
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/dec7b3c3/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java
index 1e40bb0..cc2a9aa 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/EntityService.java
@@ -23,6 +23,8 @@ import com.google.inject.Inject;
 import java.util.Collection;
 import java.util.Set;
 import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
+import org.apache.ibatis.session.SqlSession;
+import org.mybatis.guice.transactional.Transactional;
 
 /**
  * Service which provides convenience methods for creating, retrieving, and
@@ -43,6 +45,12 @@ public class EntityService {
     private EntityMapper entityMapper;
 
     /**
+     * The current SQL session used by MyBatis.
+     */
+    @Inject
+    private SqlSession sqlSession;
+
+    /**
      * Returns the set of all group identifiers of which the given entity is a
      * member, taking into account the given collection of known group
      * memberships which are not necessarily defined within the database.
@@ -64,20 +72,22 @@ public class EntityService {
      *     member of, including those where membership is inherited through
      *     membership in other groups.
      */
+    @Transactional
     public Set<String> retrieveEffectiveGroups(ModeledPermissions<? extends EntityModel> entity,
             Collection<String> effectiveGroups) {
 
         // Retrieve the effective user groups of the given entity, recursively if possible
-        Set<String> identifiers = entityMapper.selectEffectiveGroupIdentifiers(entity.getModel(), effectiveGroups);
+        boolean recursive = environment.isRecursiveQuerySupported(sqlSession);
+        Set<String> identifiers = entityMapper.selectEffectiveGroupIdentifiers(entity.getModel(), effectiveGroups, recursive);
 
         // If the set of user groups retrieved was not produced recursively,
         // manually repeat the query to expand the set until all effective
         // groups have been found
-        if (!environment.isRecursiveQuerySupported() && !identifiers.isEmpty()) {
+        if (!recursive && !identifiers.isEmpty()) {
             Set<String> previousIdentifiers;
             do {
                 previousIdentifiers = identifiers;
-                identifiers = entityMapper.selectEffectiveGroupIdentifiers(entity.getModel(), previousIdentifiers);
+                identifiers = entityMapper.selectEffectiveGroupIdentifiers(entity.getModel(), previousIdentifiers, false);
             } while (identifiers.size() > previousIdentifiers.size());
         }
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/dec7b3c3/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLEnvironment.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLEnvironment.java
index 062d6df..7a93151 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLEnvironment.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLEnvironment.java
@@ -19,11 +19,16 @@
 
 package org.apache.guacamole.auth.mysql;
 
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.guacamole.auth.jdbc.security.PasswordPolicy;
+import org.apache.ibatis.exceptions.PersistenceException;
+import org.apache.ibatis.session.SqlSession;
 
 /**
  * A MySQL-specific implementation of JDBCEnvironment provides database
@@ -35,7 +40,17 @@ public class MySQLEnvironment extends JDBCEnvironment {
      * Logger for this class.
      */
     private static final Logger logger = LoggerFactory.getLogger(MySQLEnvironment.class);
-    
+
+    /**
+     * The earliest version of MariaDB that supported recursive CTEs.
+     */
+    private static final MySQLVersion MARIADB_SUPPORTS_CTE = new MySQLVersion(10, 2, 2, true);
+
+    /**
+     * The earliest version of MySQL that supported recursive CTEs.
+     */
+    private static final MySQLVersion MYSQL_SUPPORTS_CTE = new MySQLVersion(8, 0, 1, false);
+
     /**
      * The default host to connect to, if MYSQL_HOSTNAME is not specified.
      */
@@ -227,8 +242,39 @@ public class MySQLEnvironment extends JDBCEnvironment {
     }
 
     @Override
-    public boolean isRecursiveQuerySupported() {
-        return false; // Only very recent versions of MySQL / MariaDB support recursive queries through CTEs
+    public boolean isRecursiveQuerySupported(SqlSession session) {
+
+        // Retrieve database version string from JDBC connection
+        String versionString;
+        try {
+            Connection connection = session.getConnection();
+            DatabaseMetaData metaData = connection.getMetaData();
+            versionString = metaData.getDatabaseProductVersion();
+        }
+        catch (SQLException e) {
+            throw new PersistenceException("Cannot determine whether "
+                    + "MySQL / MariaDB supports recursive queries.", e);
+        }
+
+        try {
+
+            // Parse MySQL / MariaDB version from version string
+            MySQLVersion version = new MySQLVersion(versionString);
+            logger.debug("Database recognized as {}.", version);
+
+            // Recursive queries are supported for MariaDB 10.2.2+ and
+            // MySQL 8.0.1+
+            return version.isAtLeast(MARIADB_SUPPORTS_CTE)
+                || version.isAtLeast(MYSQL_SUPPORTS_CTE);
+
+        }
+        catch (IllegalArgumentException e) {
+            logger.debug("Unrecognized MySQL / MariaDB version string: "
+                    + "\"{}\". Assuming database engine does not support "
+                    + "recursive queries.", session);
+            return false;
+        }
+
     }
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/dec7b3c3/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLVersion.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLVersion.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLVersion.java
new file mode 100644
index 0000000..577506e
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/org/apache/guacamole/auth/mysql/MySQLVersion.java
@@ -0,0 +1,153 @@
+/*
+ * 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.mysql;
+
+import com.google.common.collect.ComparisonChain;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * The specific version of a MySQL or MariaDB server.
+ */
+public class MySQLVersion {
+
+    /**
+     * Pattern which matches the version string returned by a MariaDB server,
+     * extracting the major, minor, and patch numbers.
+     */
+    private final Pattern MARIADB_VERSION = Pattern.compile("^.*-([0-9]+)\\.([0-9]+)\\.([0-9]+)-MariaDB$");
+
+    /**
+     * Pattern which matches the version string returned by a non-MariaDB
+     * server (including MySQL and Aurora), extracting the major, minor, and
+     * patch numbers. All non-MariaDB servers use normal MySQL version numbers.
+     */
+    private final Pattern MYSQL_VERSION = Pattern.compile("^([0-9]+)\\.([0-9]+)\\.([0-9]+).*$");
+
+    /**
+     * Whether the associated server is a MariaDB server. All non-MariaDB
+     * servers use normal MySQL version numbers and are comparable against each
+     * other.
+     */
+    private final boolean isMariaDB;
+
+    /**
+     * The major component of the MAJOR.MINOR.PATCH version number.
+     */
+    private final int major;
+
+    /**
+     * The minor component of the MAJOR.MINOR.PATCH version number.
+     */
+    private final int minor;
+
+    /**
+     * The patch component of the MAJOR.MINOR.PATCH version number.
+     */
+    private final int patch;
+
+    /**
+     * Creates a new MySQLVersion having the specified major, minor, and patch
+     * components.
+     *
+     * @param major
+     *     The major component of the MAJOR.MINOR.PATCH version number of the
+     *     MariaDB / MySQL server.
+     *
+     * @param minor
+     *     The minor component of the MAJOR.MINOR.PATCH version number of the
+     *     MariaDB / MySQL server.
+     *
+     * @param patch
+     *     The patch component of the MAJOR.MINOR.PATCH version number of the
+     *     MariaDB / MySQL server.
+     *
+     * @param isMariaDB
+     *     Whether the associated server is a MariaDB server.
+     */
+    public MySQLVersion(int major, int minor, int patch, boolean isMariaDB) {
+        this.major = major;
+        this.minor = minor;
+        this.patch = patch;
+        this.isMariaDB = isMariaDB;
+    }
+
+    public MySQLVersion(String version) throws IllegalArgumentException {
+
+        // Extract MariaDB version number if version string appears to be
+        // a MariaDB version string
+        Matcher mariadb = MARIADB_VERSION.matcher(version);
+        if (mariadb.matches()) {
+            this.major = Integer.parseInt(mariadb.group(1));
+            this.minor = Integer.parseInt(mariadb.group(2));
+            this.patch = Integer.parseInt(mariadb.group(3));
+            this.isMariaDB = true;
+            return;
+        }
+
+        // If not MariaDB, assume version string is a MySQL version string
+        // and attempt to extract the version number
+        Matcher mysql = MYSQL_VERSION.matcher(version);
+        if (mysql.matches()) {
+            this.major = Integer.parseInt(mysql.group(1));
+            this.minor = Integer.parseInt(mysql.group(2));
+            this.patch = Integer.parseInt(mysql.group(3));
+            this.isMariaDB = false;
+            return;
+        }
+
+        throw new IllegalArgumentException("Unrecognized MySQL / MariaDB version string.");
+
+    }
+
+    /**
+     * Returns whether this version is at least as recent as the given version.
+     *
+     * @param version
+     *     The version to compare against.
+     *
+     * @return
+     *     true if the versions are associated with the same database server
+     *     type (MariaDB vs. MySQL) and this version is at least as recent as
+     *     the given version, false otherwise.
+     */
+    public boolean isAtLeast(MySQLVersion version) {
+
+        // If the databases use different version numbering schemes, the
+        // version numbers are not comparable
+        if (isMariaDB != version.isMariaDB)
+            return false;
+
+        // Compare major, minor, and patch number in order of precedence
+        return ComparisonChain.start()
+                .compare(major, version.major)
+                .compare(minor, version.minor)
+                .compare(patch, version.patch)
+                .result() >= 0;
+
+    }
+
+    @Override
+    public String toString() {
+        return String.format("%s %d.%d.%d", isMariaDB ? "MariaDB" : "MySQL",
+                major, minor, patch);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/dec7b3c3/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
index eb7a771..21efb99 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/base/EntityMapper.xml
@@ -65,43 +65,76 @@
     <!-- Select names of all effective groups (including inherited) -->
     <select id="selectEffectiveGroupIdentifiers" resultType="string">
 
-        WITH RECURSIVE related_entity(entity_id) AS (
-                SELECT
-                    guacamole_user_group.entity_id
-                FROM guacamole_user_group
-                JOIN guacamole_user_group_member ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
-                WHERE
+        <if test="!recursive">
+            SELECT
+                guacamole_entity.name
+            FROM guacamole_user_group
+            JOIN guacamole_entity ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+            JOIN guacamole_user_group_member ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
+            WHERE
+                guacamole_user_group.disabled = false
+                AND (
                     guacamole_user_group_member.member_entity_id = #{entity.entityID}
-                    AND guacamole_user_group.disabled = false
-            <if test="!effectiveGroups.isEmpty()">
-                UNION
+                    <if test="!effectiveGroups.isEmpty()">
+                        OR guacamole_user_group_member.member_entity_id IN (
+                            SELECT entity_id FROM guacamole_entity
+                            WHERE type = 'USER_GROUP' AND name IN
+                                <foreach collection="effectiveGroups" item="effectiveGroup"
+                                         open="(" separator="," close=")">
+                                    #{effectiveGroup,jdbcType=VARCHAR}
+                                </foreach>
+                        )
+                        OR guacamole_user_group.entity_id IN (
+                            SELECT entity_id FROM guacamole_entity
+                            WHERE type = 'USER_GROUP' AND name IN
+                                <foreach collection="effectiveGroups" item="effectiveGroup"
+                                         open="(" separator="," close=")">
+                                    #{effectiveGroup,jdbcType=VARCHAR}
+                                </foreach>
+                        )
+                    </if>
+                )
+        </if>
+
+        <if test="recursive">
+            WITH RECURSIVE related_entity(entity_id) AS (
                     SELECT
-                        guacamole_entity.entity_id
-                    FROM guacamole_entity
-                    JOIN guacamole_user_group ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+                        guacamole_user_group.entity_id
+                    FROM guacamole_user_group
+                    JOIN guacamole_user_group_member ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
                     WHERE
-                        type = 'USER_GROUP'
-                        AND name IN
-                            <foreach collection="effectiveGroups" item="effectiveGroup"
-                                     open="(" separator="," close=")">
-                                #{effectiveGroup,jdbcType=VARCHAR}
-                            </foreach>
+                        guacamole_user_group_member.member_entity_id = #{entity.entityID}
                         AND guacamole_user_group.disabled = false
-            </if>
-            UNION
-                SELECT
-                    guacamole_user_group.entity_id
-                FROM related_entity
-                JOIN guacamole_user_group_member ON related_entity.entity_id = guacamole_user_group_member.member_entity_id
-                JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
-                WHERE
-                    guacamole_user_group.disabled = false
-        )
-        SELECT name
-        FROM related_entity
-        JOIN guacamole_entity ON related_entity.entity_id = guacamole_entity.entity_id
-        WHERE
-            guacamole_entity.type = 'USER_GROUP';
+                <if test="!effectiveGroups.isEmpty()">
+                    UNION
+                        SELECT
+                            guacamole_entity.entity_id
+                        FROM guacamole_entity
+                        JOIN guacamole_user_group ON guacamole_user_group.entity_id = guacamole_entity.entity_id
+                        WHERE
+                            type = 'USER_GROUP'
+                            AND name IN
+                                <foreach collection="effectiveGroups" item="effectiveGroup"
+                                         open="(" separator="," close=")">
+                                    #{effectiveGroup,jdbcType=VARCHAR}
+                                </foreach>
+                            AND guacamole_user_group.disabled = false
+                </if>
+                UNION
+                    SELECT
+                        guacamole_user_group.entity_id
+                    FROM related_entity
+                    JOIN guacamole_user_group_member ON related_entity.entity_id = guacamole_user_group_member.member_entity_id
+                    JOIN guacamole_user_group ON guacamole_user_group.user_group_id = guacamole_user_group_member.user_group_id
+                    WHERE
+                        guacamole_user_group.disabled = false
+            )
+            SELECT name
+            FROM related_entity
+            JOIN guacamole_entity ON related_entity.entity_id = guacamole_entity.entity_id
+            WHERE
+                guacamole_entity.type = 'USER_GROUP';
+        </if>
 
     </select>
 

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/dec7b3c3/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLEnvironment.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLEnvironment.java
index d5d259e..4ac99e8 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLEnvironment.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/apache/guacamole/auth/postgresql/PostgreSQLEnvironment.java
@@ -24,6 +24,7 @@ import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.guacamole.auth.jdbc.security.PasswordPolicy;
+import org.apache.ibatis.session.SqlSession;
 
 /**
  * A PostgreSQL-specific implementation of JDBCEnvironment provides database
@@ -244,7 +245,7 @@ public class PostgreSQLEnvironment extends JDBCEnvironment {
     }
 
     @Override
-    public boolean isRecursiveQuerySupported() {
+    public boolean isRecursiveQuerySupported(SqlSession session) {
         return true; // All versions of PostgreSQL support recursive queries through CTEs
     }
     

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/dec7b3c3/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerEnvironment.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerEnvironment.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerEnvironment.java
index 03f2cf8..db068b9 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerEnvironment.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/java/org/apache/guacamole/auth/sqlserver/SQLServerEnvironment.java
@@ -24,6 +24,7 @@ import org.apache.guacamole.auth.jdbc.JDBCEnvironment;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.apache.guacamole.auth.jdbc.security.PasswordPolicy;
+import org.apache.ibatis.session.SqlSession;
 
 /**
  * A SQLServer-specific implementation of JDBCEnvironment provides database
@@ -252,7 +253,7 @@ public class SQLServerEnvironment extends JDBCEnvironment {
     }
 
     @Override
-    public boolean isRecursiveQuerySupported() {
+    public boolean isRecursiveQuerySupported(SqlSession session) {
         return true; // All versions of SQL Server support recursive queries through CTEs
     }