From 624d49847c83faac302a7fbc9dd35f59e25d795e Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 26 Oct 2020 23:54:58 -0700 Subject: [PATCH] GUACAMOLE-1021: Refactor SQL Server queries to NOT duplicate results across related entities. Previous versions of the SQL Server queries relied on permission for each object being granted from exactly one location, thus allowing queries to be narrowed by permission using a simple JOIN. This is no longer the case, as permissions may be inherited from multiple locations (groups). --- .../auth/jdbc/connection/ConnectionMapper.xml | 83 +++++++++------- .../connection/ConnectionRecordMapper.xml | 38 ++++---- .../connectiongroup/ConnectionGroupMapper.xml | 96 +++++++++++-------- .../ConnectionGroupPermissionMapper.xml | 2 +- .../permission/ConnectionPermissionMapper.xml | 2 +- .../SharingProfilePermissionMapper.xml | 2 +- .../permission/UserGroupPermissionMapper.xml | 2 +- .../jdbc/permission/UserPermissionMapper.xml | 2 +- .../sharingprofile/SharingProfileMapper.xml | 57 +++++++---- .../guacamole/auth/jdbc/user/UserMapper.xml | 65 +++++++++---- .../jdbc/user/UserParentUserGroupMapper.xml | 13 ++- .../auth/jdbc/user/UserRecordMapper.xml | 20 ++-- .../auth/jdbc/usergroup/UserGroupMapper.xml | 65 +++++++++---- .../UserGroupMemberUserGroupMapper.xml | 13 ++- .../usergroup/UserGroupMemberUserMapper.xml | 13 ++- .../UserGroupParentUserGroupMapper.xml | 13 ++- 16 files changed, 287 insertions(+), 199 deletions(-) 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 54cb575c0..7b1adae8e 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 @@ -63,17 +63,38 @@ FROM [guacamole_connection] - - + + + + @@ -89,16 +110,15 @@ @@ -172,51 +192,48 @@ WHERE [guacamole_connection_history].connection_id = [guacamole_connection].connection_id ) AS last_active FROM [guacamole_connection] - JOIN [guacamole_connection_permission] ON [guacamole_connection_permission].connection_id = [guacamole_connection].connection_id WHERE [guacamole_connection].connection_id IN #{identifier,jdbcType=INTEGER} - AND - - - - - AND permission = 'READ'; + AND [guacamole_connection].connection_id IN ( + + + + + ); SELECT primary_connection_id, [guacamole_sharing_profile].sharing_profile_id FROM [guacamole_sharing_profile] - JOIN [guacamole_sharing_profile_permission] ON [guacamole_sharing_profile_permission].sharing_profile_id = [guacamole_sharing_profile].sharing_profile_id WHERE primary_connection_id IN #{identifier,jdbcType=INTEGER} - AND - - - - - AND permission = 'READ'; + AND [guacamole_sharing_profile].sharing_profile_id IN ( + + + + + ); SELECT [guacamole_connection_attribute].connection_id, attribute_name, attribute_value FROM [guacamole_connection_attribute] - JOIN [guacamole_connection_permission] ON [guacamole_connection_permission].connection_id = [guacamole_connection_attribute].connection_id WHERE [guacamole_connection_attribute].connection_id IN #{identifier,jdbcType=INTEGER} - AND - - - - - AND permission = 'READ'; + AND [guacamole_connection_attribute].connection_id IN ( + + + + + ); 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 e24f2e863..0ea14cc85 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 @@ -168,31 +168,27 @@ LEFT JOIN [guacamole_connection] ON [guacamole_connection_history].connection_id = [guacamole_connection].connection_id LEFT JOIN [guacamole_user] ON [guacamole_connection_history].user_id = [guacamole_user].user_id - - JOIN [guacamole_connection_permission] ON - [guacamole_connection_history].connection_id = [guacamole_connection_permission].connection_id - AND - - - - - AND [guacamole_connection_permission].permission = 'READ' - - - JOIN [guacamole_user_permission] ON - [guacamole_connection_history].user_id = [guacamole_user_permission].affected_user_id - AND - - - - - AND [guacamole_user_permission].permission = 'READ' - + + [guacamole_connection_history].connection_id IN ( + + + + + ) + + + AND [guacamole_connection_history].user_id IN ( + + + + + ) + - [guacamole_connection_history].connection_id = #{identifier,jdbcType=INTEGER} + AND [guacamole_connection_history].connection_id = #{identifier,jdbcType=INTEGER} 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 32c1d1348..4bc8a2796 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 @@ -64,17 +64,38 @@ FROM [guacamole_connection_group] - - + + + + @@ -90,16 +111,15 @@ @@ -163,66 +183,62 @@ max_connections_per_user, enable_session_affinity FROM [guacamole_connection_group] - JOIN [guacamole_connection_group_permission] ON [guacamole_connection_group_permission].connection_group_id = [guacamole_connection_group].connection_group_id WHERE [guacamole_connection_group].connection_group_id IN #{identifier,jdbcType=INTEGER} - AND - - - - - AND permission = 'READ'; + AND [guacamole_connection_group].connection_group_id IN ( + + + + + ); SELECT parent_id, [guacamole_connection_group].connection_group_id FROM [guacamole_connection_group] - JOIN [guacamole_connection_group_permission] ON [guacamole_connection_group_permission].connection_group_id = [guacamole_connection_group].connection_group_id WHERE parent_id IN #{identifier,jdbcType=INTEGER} - AND - - - - - AND permission = 'READ'; + AND [guacamole_connection_group].connection_group_id IN ( + + + + + ); SELECT parent_id, [guacamole_connection].connection_id FROM [guacamole_connection] - JOIN [guacamole_connection_permission] ON [guacamole_connection_permission].connection_id = [guacamole_connection].connection_id WHERE parent_id IN #{identifier,jdbcType=INTEGER} - AND - - - - - AND permission = 'READ'; + AND [guacamole_connection].connection_id IN ( + + + + + ); SELECT [guacamole_connection_group_attribute].connection_group_id, attribute_name, attribute_value FROM [guacamole_connection_group_attribute] - JOIN [guacamole_connection_group_permission] ON [guacamole_connection_group_permission].connection_group_id = [guacamole_connection_group_attribute].connection_group_id WHERE [guacamole_connection_group_attribute].connection_group_id IN #{identifier,jdbcType=INTEGER} - AND - - - - - AND permission = 'READ'; + AND [guacamole_connection_group_attribute].connection_group_id IN ( + + + + + ); 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 ef58daf3d..23cef25e3 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 @@ -34,7 +34,7 @@ - SELECT + SELECT DISTINCT #{entity.entityID,jdbcType=INTEGER} AS entity_id, permission, connection_id 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 23feeeeaf..bb45e4bbc 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 @@ -34,7 +34,7 @@ - SELECT + SELECT DISTINCT #{entity.entityID,jdbcType=INTEGER} AS entity_id, permission, affected_entity.name AS affected_name 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 450341921..5c088045e 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 @@ -34,7 +34,7 @@ - - + + + + @@ -97,36 +118,34 @@ [guacamole_sharing_profile].sharing_profile_name, primary_connection_id FROM [guacamole_sharing_profile] - JOIN [guacamole_sharing_profile_permission] ON [guacamole_sharing_profile_permission].sharing_profile_id = [guacamole_sharing_profile].sharing_profile_id WHERE [guacamole_sharing_profile].sharing_profile_id IN #{identifier,jdbcType=INTEGER} - AND - - - - - AND permission = 'READ'; + AND [guacamole_sharing_profile].sharing_profile_id IN ( + + + + + ); SELECT [guacamole_sharing_profile_attribute].sharing_profile_id, attribute_name, attribute_value FROM [guacamole_sharing_profile_attribute] - JOIN [guacamole_sharing_profile_permission] ON [guacamole_sharing_profile_permission].sharing_profile_id = [guacamole_sharing_profile_attribute].sharing_profile_id WHERE [guacamole_sharing_profile_attribute].sharing_profile_id IN #{identifier,jdbcType=INTEGER} - AND - - - - - AND permission = 'READ'; + AND [guacamole_sharing_profile_attribute].sharing_profile_id IN ( + + + + + ); 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 7d70950af..80344968b 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 @@ -63,20 +63,45 @@ WHERE [guacamole_entity].type = 'USER' + + + SELECT DISTINCT [guacamole_user_permission].affected_user_id + FROM [guacamole_user_permission] + WHERE + + + + + + AND permission = 'READ' + + @@ -160,19 +185,18 @@ ) 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_entity].name IN #{identifier,jdbcType=VARCHAR} AND [guacamole_entity].type = 'USER' - AND - - - - - AND permission = 'READ'; + AND [guacamole_user].user_id IN ( + + + + + ); SELECT [guacamole_user_attribute].user_id, @@ -181,19 +205,18 @@ 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 [guacamole_entity].name IN #{identifier,jdbcType=VARCHAR} AND [guacamole_entity].type = 'USER' - AND - - - - - AND permission = 'READ'; + AND [guacamole_user].user_id IN ( + + + + + ); 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 index e6eccba96..ee67931ad 100644 --- 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 @@ -40,16 +40,15 @@ 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 - - - - - + [guacamole_user_group].user_group_id IN ( + + + + + ) AND [guacamole_user_group_member].member_entity_id = #{parent.entityID,jdbcType=INTEGER} AND [guacamole_entity].type = 'USER_GROUP' - AND permission = 'READ' 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 179ef39ae..8518e7097 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 @@ -158,21 +158,19 @@ [guacamole_user_history].end_date FROM [guacamole_user_history] - - JOIN [guacamole_user_permission] ON - [guacamole_user_history].user_id = [guacamole_user_permission].affected_user_id - AND - - - - - AND [guacamole_user_permission].permission = 'READ' - + + + [guacamole_connection_history].user_id IN ( + + + + + ) - [guacamole_entity].name = #{username,jdbcType=VARCHAR} + AND [guacamole_entity].name = #{username,jdbcType=VARCHAR} 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 index aed0247be..21c776aa1 100644 --- 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 @@ -49,20 +49,45 @@ WHERE [guacamole_entity].type = 'USER_GROUP' + + + SELECT DISTINCT [guacamole_user_group_permission].affected_user_group_id + FROM [guacamole_user_group_permission] + WHERE + + + + + + AND permission = 'READ' + + @@ -110,19 +135,18 @@ 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 #{identifier,jdbcType=VARCHAR} AND [guacamole_entity].type = 'USER_GROUP' - AND - - - - - AND permission = 'READ'; + AND [guacamole_user_group].user_group_id IN ( + + + + + ); SELECT [guacamole_user_group_attribute].user_group_id, @@ -131,19 +155,18 @@ 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 #{identifier,jdbcType=VARCHAR} AND [guacamole_entity].type = 'USER_GROUP' - AND - - - - - AND permission = 'READ'; + AND [guacamole_user_group].user_group_id IN ( + + + + + ); 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 index 2092f24e9..b11a3c529 100644 --- 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 @@ -39,16 +39,15 @@ 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 - - - - - + [guacamole_user_group].user_group_id IN ( + + + + + ) AND [guacamole_user_group_member].user_group_id = #{parent.objectID,jdbcType=INTEGER} AND [guacamole_entity].type = 'USER_GROUP' - AND permission = 'READ' 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 index 2c91c92c2..b0682b041 100644 --- 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 @@ -39,16 +39,15 @@ 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 - - - - - + [guacamole_user].user_id IN ( + + + + + ) AND [guacamole_user_group_member].user_group_id = #{parent.objectID,jdbcType=INTEGER} AND [guacamole_entity].type = 'USER' - AND permission = 'READ' 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 index 0ea9252e7..198a6244d 100644 --- 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 @@ -40,16 +40,15 @@ 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 - - - - - + [guacamole_user_group].user_group_id IN ( + + + + + ) AND [guacamole_user_group_member].member_entity_id = #{parent.entityID,jdbcType=INTEGER} AND [guacamole_entity].type = 'USER_GROUP' - AND permission = 'READ'