From 94b691b0768c0e71aedd29672fbb4afae0cac615 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Thu, 4 Jul 2024 11:57:52 -0400 Subject: [PATCH] GUACAMOLE-1957: Support granular permissions management. --- .../directives/connectionPermissionEditor.js | 124 ++++++++++-------- .../src/app/manage/styles/permissions.css | 61 +++++++++ .../templates/connectionGroupPermission.html | 47 ++++++- .../templates/connectionPermission.html | 48 ++++++- .../templates/sharingProfilePermission.html | 48 ++++++- .../main/frontend/src/translations/en.json | 9 ++ 6 files changed, 271 insertions(+), 66 deletions(-) create mode 100644 guacamole/src/main/frontend/src/app/manage/styles/permissions.css diff --git a/guacamole/src/main/frontend/src/app/manage/directives/connectionPermissionEditor.js b/guacamole/src/main/frontend/src/app/manage/directives/connectionPermissionEditor.js index 9392bb0fc2..1bf4f0b94c 100644 --- a/guacamole/src/main/frontend/src/app/manage/directives/connectionPermissionEditor.js +++ b/guacamole/src/main/frontend/src/app/manage/directives/connectionPermissionEditor.js @@ -34,6 +34,7 @@ angular.module('manage').directive('connectionPermissionEditor', ['$injector', var connectionGroupService = $injector.get('connectionGroupService'); var dataSourceService = $injector.get('dataSourceService'); var requestService = $injector.get('requestService'); + var $log = $injector.get('$log'); var directive = { @@ -355,17 +356,20 @@ angular.module('manage').directive('connectionPermissionEditor', ['$injector', * to reflect the addition of the given connection permission. * * @param {String} identifier - * The identifier of the connection to add READ permission for. + * The identifier of the connection to add a permission for. + * + * @param {ObjectPermissionType} permission + * The permission to add. */ - var addConnectionPermission = function addConnectionPermission(identifier) { + var addConnectionPermission = function addConnectionPermission(identifier, permission) { // If permission was previously removed, simply un-remove it - if (PermissionSet.hasConnectionPermission($scope.permissionsRemoved, PermissionSet.ObjectPermissionType.READ, identifier)) - PermissionSet.removeConnectionPermission($scope.permissionsRemoved, PermissionSet.ObjectPermissionType.READ, identifier); + if (PermissionSet.hasConnectionPermission($scope.permissionsRemoved, permission, identifier)) + PermissionSet.removeConnectionPermission($scope.permissionsRemoved, permission, identifier); // Otherwise, explicitly add the permission else - PermissionSet.addConnectionPermission($scope.permissionsAdded, PermissionSet.ObjectPermissionType.READ, identifier); + PermissionSet.addConnectionPermission($scope.permissionsAdded, permission, identifier); }; @@ -374,17 +378,20 @@ angular.module('manage').directive('connectionPermissionEditor', ['$injector', * to reflect the removal of the given connection permission. * * @param {String} identifier - * The identifier of the connection to remove READ permission for. + * The identifier of the connection to remove a permission for. + * + * @param {ObjectPermissionType} permission + * The permission to remove. */ - var removeConnectionPermission = function removeConnectionPermission(identifier) { + var removeConnectionPermission = function removeConnectionPermission(identifier, permission) { // If permission was previously added, simply un-add it - if (PermissionSet.hasConnectionPermission($scope.permissionsAdded, PermissionSet.ObjectPermissionType.READ, identifier)) - PermissionSet.removeConnectionPermission($scope.permissionsAdded, PermissionSet.ObjectPermissionType.READ, identifier); + if (PermissionSet.hasConnectionPermission($scope.permissionsAdded, permission, identifier)) + PermissionSet.removeConnectionPermission($scope.permissionsAdded, permission, identifier); // Otherwise, explicitly remove the permission else - PermissionSet.addConnectionPermission($scope.permissionsRemoved, PermissionSet.ObjectPermissionType.READ, identifier); + PermissionSet.addConnectionPermission($scope.permissionsRemoved, permission, identifier); }; @@ -393,18 +400,20 @@ angular.module('manage').directive('connectionPermissionEditor', ['$injector', * to reflect the addition of the given connection group permission. * * @param {String} identifier - * The identifier of the connection group to add READ permission - * for. + * The identifier of the connection group to add a permission for. + * + * @param {ObjectPermissionType} permission + * The permission to add. */ - var addConnectionGroupPermission = function addConnectionGroupPermission(identifier) { + var addConnectionGroupPermission = function addConnectionGroupPermission(identifier, permission) { // If permission was previously removed, simply un-remove it - if (PermissionSet.hasConnectionGroupPermission($scope.permissionsRemoved, PermissionSet.ObjectPermissionType.READ, identifier)) - PermissionSet.removeConnectionGroupPermission($scope.permissionsRemoved, PermissionSet.ObjectPermissionType.READ, identifier); + if (PermissionSet.hasConnectionGroupPermission($scope.permissionsRemoved, permission, identifier)) + PermissionSet.removeConnectionGroupPermission($scope.permissionsRemoved, permission, identifier); // Otherwise, explicitly add the permission else - PermissionSet.addConnectionGroupPermission($scope.permissionsAdded, PermissionSet.ObjectPermissionType.READ, identifier); + PermissionSet.addConnectionGroupPermission($scope.permissionsAdded, permission, identifier); }; @@ -413,18 +422,20 @@ angular.module('manage').directive('connectionPermissionEditor', ['$injector', * to reflect the removal of the given connection group permission. * * @param {String} identifier - * The identifier of the connection group to remove READ permission - * for. + * The identifier of the connection group to remove a permission for. + * + * @param {ObjectPermissionType} permission + * The permission to remove. */ - var removeConnectionGroupPermission = function removeConnectionGroupPermission(identifier) { + var removeConnectionGroupPermission = function removeConnectionGroupPermission(identifier, permission) { // If permission was previously added, simply un-add it - if (PermissionSet.hasConnectionGroupPermission($scope.permissionsAdded, PermissionSet.ObjectPermissionType.READ, identifier)) - PermissionSet.removeConnectionGroupPermission($scope.permissionsAdded, PermissionSet.ObjectPermissionType.READ, identifier); + if (PermissionSet.hasConnectionGroupPermission($scope.permissionsAdded, permission, identifier)) + PermissionSet.removeConnectionGroupPermission($scope.permissionsAdded, permission, identifier); // Otherwise, explicitly remove the permission else - PermissionSet.addConnectionGroupPermission($scope.permissionsRemoved, PermissionSet.ObjectPermissionType.READ, identifier); + PermissionSet.addConnectionGroupPermission($scope.permissionsRemoved, permission, identifier); }; @@ -433,17 +444,20 @@ angular.module('manage').directive('connectionPermissionEditor', ['$injector', * to reflect the addition of the given sharing profile permission. * * @param {String} identifier - * The identifier of the sharing profile to add READ permission for. + * The identifier of the sharing profile to add a permission for. + * + * @param {ObjectPermissionType} permission + * The permission to add. */ - var addSharingProfilePermission = function addSharingProfilePermission(identifier) { + var addSharingProfilePermission = function addSharingProfilePermission(identifier, permission) { // If permission was previously removed, simply un-remove it - if (PermissionSet.hasSharingProfilePermission($scope.permissionsRemoved, PermissionSet.ObjectPermissionType.READ, identifier)) - PermissionSet.removeSharingProfilePermission($scope.permissionsRemoved, PermissionSet.ObjectPermissionType.READ, identifier); + if (PermissionSet.hasSharingProfilePermission($scope.permissionsRemoved, permission, identifier)) + PermissionSet.removeSharingProfilePermission($scope.permissionsRemoved, permission, identifier); // Otherwise, explicitly add the permission else - PermissionSet.addSharingProfilePermission($scope.permissionsAdded, PermissionSet.ObjectPermissionType.READ, identifier); + PermissionSet.addSharingProfilePermission($scope.permissionsAdded, permission, identifier); }; @@ -452,18 +466,20 @@ angular.module('manage').directive('connectionPermissionEditor', ['$injector', * to reflect the removal of the given sharing profile permission. * * @param {String} identifier - * The identifier of the sharing profile to remove READ permission - * for. + * The identifier of the sharing profile to remove a permission for. + * + * @param {ObjectPermissionType} permission + * The permission to remove. */ - var removeSharingProfilePermission = function removeSharingProfilePermission(identifier) { + var removeSharingProfilePermission = function removeSharingProfilePermission(identifier, permission) { // If permission was previously added, simply un-add it - if (PermissionSet.hasSharingProfilePermission($scope.permissionsAdded, PermissionSet.ObjectPermissionType.READ, identifier)) - PermissionSet.removeSharingProfilePermission($scope.permissionsAdded, PermissionSet.ObjectPermissionType.READ, identifier); + if (PermissionSet.hasSharingProfilePermission($scope.permissionsAdded, permission, identifier)) + PermissionSet.removeSharingProfilePermission($scope.permissionsAdded, permission, identifier); // Otherwise, explicitly remove the permission else - PermissionSet.addSharingProfilePermission($scope.permissionsRemoved, PermissionSet.ObjectPermissionType.READ, identifier); + PermissionSet.addSharingProfilePermission($scope.permissionsRemoved, permission, identifier); }; @@ -493,14 +509,14 @@ angular.module('manage').directive('connectionPermissionEditor', ['$injector', */ connectionPermissionChanged : function connectionPermissionChanged(identifier) { - // Determine current permission setting - var granted = $scope.permissionFlags.connectionPermissions.READ[identifier]; + // Loop through permissions to add or remove them as required. + for (const [key, value] of Object.entries($scope.permissionFlags.connectionPermissions)) { + if (value[identifier]) + addConnectionPermission(identifier, PermissionSet.ObjectPermissionType[key]); + else + removeConnectionPermission(identifier, PermissionSet.ObjectPermissionType[key]); - // Add/remove permission depending on flag state - if (granted) - addConnectionPermission(identifier); - else - removeConnectionPermission(identifier); + } }, @@ -515,14 +531,14 @@ angular.module('manage').directive('connectionPermissionEditor', ['$injector', */ connectionGroupPermissionChanged : function connectionGroupPermissionChanged(identifier) { - // Determine current permission setting - var granted = $scope.permissionFlags.connectionGroupPermissions.READ[identifier]; + // Loop through permissions and add or remove them as required. + for (const [key, value] of Object.entries($scope.permissionFlags.connectionGroupPermissions)) { + if (value[identifier]) + addConnectionGroupPermission(identifier, PermissionSet.ObjectPermissionType[key]); + else + removeConnectionGroupPermission(identifier, PermissionSet.ObjectPermissionType[key]); - // Add/remove permission depending on flag state - if (granted) - addConnectionGroupPermission(identifier); - else - removeConnectionGroupPermission(identifier); + } }, @@ -537,14 +553,14 @@ angular.module('manage').directive('connectionPermissionEditor', ['$injector', */ sharingProfilePermissionChanged : function sharingProfilePermissionChanged(identifier) { - // Determine current permission setting - var granted = $scope.permissionFlags.sharingProfilePermissions.READ[identifier]; + // Loop through permissions and add or remove them as required. + for (const [key, value] of Object.entries($scope.permissionFlags.sharingProfilePermissions)) { + if (value[identifier]) + addSharingProfilePermission(identifier, PermissionSet.ObjectPermissionType[key]); + else + removeSharingProfilePermission(identifier, PermissionSet.ObjectPermissionType[key]); - // Add/remove permission depending on flag state - if (granted) - addSharingProfilePermission(identifier); - else - removeSharingProfilePermission(identifier); + } } diff --git a/guacamole/src/main/frontend/src/app/manage/styles/permissions.css b/guacamole/src/main/frontend/src/app/manage/styles/permissions.css new file mode 100644 index 0000000000..866953068d --- /dev/null +++ b/guacamole/src/main/frontend/src/app/manage/styles/permissions.css @@ -0,0 +1,61 @@ +/* + * 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. + */ + +/* Draw the box for the toggle button. */ +label.permission-toggle { + position: relative; + display: inline-grid; + width: fit-content; + border: 1px solid rgba(0, 0, 0, .125); + font-weight: 300; + cursor: pointer; +} + +/* Padding around the label. */ +label.permission-toggle div { + padding: 6px; + text-align: center; + z-index: 1; +} + +/* Hide the actual checkbox */ +input.permission-toggle { + display: none; +} + +/* Style of the checked toggle. */ +input.permission-toggle:checked + label.permission-toggle div:first-child { + color: #ffffff; + transition: color 0.3s; + background: #5a5a5a; + font-size: 0.90em; + font-weight: 700; +} + +/* Style of the unchecked toggle. */ +input.permission-toggle + label.permission-toggle div:first-child { + color: rgba(0, 0, 0, .125); + transition: color 0.3s; + font-size: 0.90em; + font-weight: 700; +} + +.permission-container { + display: inline-block; +} \ No newline at end of file diff --git a/guacamole/src/main/frontend/src/app/manage/templates/connectionGroupPermission.html b/guacamole/src/main/frontend/src/app/manage/templates/connectionGroupPermission.html index 2bc90cce9e..fc0cdd3287 100644 --- a/guacamole/src/main/frontend/src/app/manage/templates/connectionGroupPermission.html +++ b/guacamole/src/main/frontend/src/app/manage/templates/connectionGroupPermission.html @@ -3,11 +3,50 @@
- - - {{item.name}} + +
+ + + + + + + + + + + + + + + + +
diff --git a/guacamole/src/main/frontend/src/app/manage/templates/connectionPermission.html b/guacamole/src/main/frontend/src/app/manage/templates/connectionPermission.html index e94f9114e9..a643874a9b 100644 --- a/guacamole/src/main/frontend/src/app/manage/templates/connectionPermission.html +++ b/guacamole/src/main/frontend/src/app/manage/templates/connectionPermission.html @@ -3,11 +3,51 @@
- - - {{item.name}} + +
+ + + + + + + + + + + + + + + + +
+ diff --git a/guacamole/src/main/frontend/src/app/manage/templates/sharingProfilePermission.html b/guacamole/src/main/frontend/src/app/manage/templates/sharingProfilePermission.html index 0d16472556..542f6650c9 100644 --- a/guacamole/src/main/frontend/src/app/manage/templates/sharingProfilePermission.html +++ b/guacamole/src/main/frontend/src/app/manage/templates/sharingProfilePermission.html @@ -3,11 +3,51 @@
- - - {{item.name}} +
+ + + + + + + + + + + + + + + + + +
+ diff --git a/guacamole/src/main/frontend/src/translations/en.json b/guacamole/src/main/frontend/src/translations/en.json index 7b5e55c65b..0e9b8fe32d 100644 --- a/guacamole/src/main/frontend/src/translations/en.json +++ b/guacamole/src/main/frontend/src/translations/en.json @@ -480,6 +480,15 @@ "TEXT_CONFIRM_DELETE" : "Groups cannot be restored after they have been deleted. Are you sure you want to delete this group?" }, + + "PERMISSIONS" : { + + "TOGGLE_PERMISSION_ADMINISTER" : "Administer", + "TOGGLE_PERMISSION_DELETE" : "Delete", + "TOGGLE_PERMISSION_CONNECT" : "Connect", + "TOGGLE_PERMISSION_UPDATE" : "Update" + + }, "PLAYER" : {