From f55f388667315a7c3be406811ff75559b52909ac Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Fri, 28 Aug 2015 14:49:44 -0700 Subject: [PATCH] GUAC-586: Add multi-source retrieval of permissions to permissionService. Use multiple sources to determine user pages. --- .../navigation/services/userPageService.js | 115 +++++++++++------- .../app/rest/services/permissionService.js | 60 ++++++++- 2 files changed, 129 insertions(+), 46 deletions(-) diff --git a/guacamole/src/main/webapp/app/navigation/services/userPageService.js b/guacamole/src/main/webapp/app/navigation/services/userPageService.js index 9489581b0..b64556bf3 100644 --- a/guacamole/src/main/webapp/app/navigation/services/userPageService.js +++ b/guacamole/src/main/webapp/app/navigation/services/userPageService.js @@ -140,64 +140,79 @@ angular.module('navigation').factory('userPageService', ['$injector', * Returns all settings pages that the current user can visit. This can * include any of the various manage pages. * - * @param {PermissionSet} permissions - * The permissions for the current user. + * @param {Object.} permissionSets + * A map of all permissions granted to the current user, where each + * key is the identifier of the corresponding data source. * * @returns {Page[]} * An array of all settings pages that the current user can visit. */ - var generateSettingsPages = function generateSettingsPages(permissions) { + var generateSettingsPages = function generateSettingsPages(permissionSets) { var pages = []; - permissions = angular.copy(permissions); + var canManageUsers = false; + var canManageConnections = false; + var canManageSessions = false; - // Ignore permission to update root group - PermissionSet.removeConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE, ConnectionGroup.ROOT_IDENTIFIER); + // Inspect the contents of each provided permission set + angular.forEach(permissionSets, function inspectPermissions(permissions) { - // Ignore permission to update self - PermissionSet.removeUserPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE, authenticationService.getCurrentUsername()); + permissions = angular.copy(permissions); - // Determine whether the current user needs access to the user management UI - var canManageUsers = + // Ignore permission to update root group + PermissionSet.removeConnectionGroupPermission(permissions, + PermissionSet.ObjectPermissionType.UPDATE, + ConnectionGroup.ROOT_IDENTIFIER); - // System permissions - PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) - || PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.CREATE_USER) + // Ignore permission to update self + PermissionSet.removeUserPermission(permissions, + PermissionSet.ObjectPermissionType.UPDATE, + authenticationService.getCurrentUsername()); - // Permission to update users - || PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE) + // Determine whether the current user needs access to the user management UI + canManageUsers = canManageUsers || - // Permission to delete users - || PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.DELETE) + // System permissions + PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) + || PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.CREATE_USER) - // Permission to administer users - || PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.ADMINISTER); + // Permission to update users + || PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE) - // Determine whether the current user needs access to the connection management UI - var canManageConnections = + // Permission to delete users + || PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.DELETE) - // System permissions - PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) - || PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.CREATE_CONNECTION) - || PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.CREATE_CONNECTION_GROUP) + // Permission to administer users + || PermissionSet.hasUserPermission(permissions, PermissionSet.ObjectPermissionType.ADMINISTER); - // Permission to update connections or connection groups - || PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE) - || PermissionSet.hasConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE) + // Determine whether the current user needs access to the connection management UI + canManageConnections = canManageConnections || - // Permission to delete connections or connection groups - || PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.DELETE) - || PermissionSet.hasConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.DELETE) + // System permissions + PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER) + || PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.CREATE_CONNECTION) + || PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.CREATE_CONNECTION_GROUP) - // Permission to administer connections or connection groups - || PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.ADMINISTER) - || PermissionSet.hasConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.ADMINISTER); + // Permission to update connections or connection groups + || PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE) + || PermissionSet.hasConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE) - var canManageSessions = + // Permission to delete connections or connection groups + || PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.DELETE) + || PermissionSet.hasConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.DELETE) - // A user must be a system administrator to manage sessions - PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER); + // Permission to administer connections or connection groups + || PermissionSet.hasConnectionPermission(permissions, PermissionSet.ObjectPermissionType.ADMINISTER) + || PermissionSet.hasConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.ADMINISTER); + + // Determine whether the current user needs access to the session management UI + canManageSessions = canManageSessions || + + // A user must be a system administrator to manage sessions + PermissionSet.hasSystemPermission(permissions, PermissionSet.SystemPermissionType.ADMINISTER); + + }); // If user can manage sessions, add link to sessions management page if (canManageSessions) { @@ -245,10 +260,14 @@ angular.module('navigation').factory('userPageService', ['$injector', var deferred = $q.defer(); - // Retrieve current permissions, resolving main pages if possible + // Retrieve current permissions + permissionService.getAllPermissions( + authenticationService.getAvailableDataSources(), + authenticationService.getCurrentUsername() + ) + // Resolve promise using settings pages derived from permissions - permissionService.getPermissions(authenticationService.getCurrentUsername()) - .success(function permissionsRetrieved(permissions) { + .then(function permissionsRetrieved(permissions) { deferred.resolve(generateSettingsPages(permissions)); }); @@ -264,8 +283,9 @@ angular.module('navigation').factory('userPageService', ['$injector', * @param {ConnectionGroup} rootGroup * The root of the connection group tree for the current user. * - * @param {PermissionSet} permissions - * The permissions for the current user. + * @param {Object.} permissions + * A map of all permissions granted to the current user, where each + * key is the identifier of the corresponding data source. * * @returns {Page[]} * An array of all main pages that the current user can visit. @@ -327,9 +347,14 @@ angular.module('navigation').factory('userPageService', ['$injector', resolveMainPages(); }); - // Retrieve current permissions, resolving main pages if possible - permissionService.getPermissions(authenticationService.getCurrentUsername()) - .success(function permissionsRetrieved(retrievedPermissions) { + // Retrieve current permissions + permissionService.getAllPermissions( + authenticationService.getAvailableDataSources(), + authenticationService.getCurrentUsername() + ) + + // Resolving main pages if possible + .then(function permissionsRetrieved(retrievedPermissions) { permissions = retrievedPermissions; resolveMainPages(); }); diff --git a/guacamole/src/main/webapp/app/rest/services/permissionService.js b/guacamole/src/main/webapp/app/rest/services/permissionService.js index ee15804a8..ca9a2ef89 100644 --- a/guacamole/src/main/webapp/app/rest/services/permissionService.js +++ b/guacamole/src/main/webapp/app/rest/services/permissionService.js @@ -28,6 +28,7 @@ angular.module('rest').factory('permissionService', ['$injector', // Required services var $http = $injector.get('$http'); + var $q = $injector.get('$q'); var authenticationService = $injector.get('authenticationService'); var cacheService = $injector.get('cacheService'); @@ -69,7 +70,64 @@ angular.module('rest').factory('permissionService', ['$injector', }); }; - + + /** + * Returns a promise which resolves with all permissions available to the + * given user, as a map of all PermissionSet objects by the identifier of + * their corresponding data source. All given data sources are queried. If + * an error occurs while retrieving any PermissionSet, the promise will be + * rejected. + * + * @param {String[]} dataSources + * The unique identifier of the data sources containing the user whose + * permissions should be retrieved. These identifiers corresponds to + * AuthenticationProviders within the Guacamole web application. + * + * @param {String} username + * The username of the user to retrieve the permissions for. + * + * @returns {Promise.>} + * A promise which resolves with all permissions available to the + * current user, as a map of app PermissionSet objects by the + * identifier of their corresponding data source. + */ + service.getAllPermissions = function getAllPermissions(dataSources, username) { + + var deferred = $q.defer(); + + var permissionSetRequests = []; + var permissionSets = {}; + + // Retrieve all permissions from all data sources + angular.forEach(dataSources, function retrievePermissions(dataSource) { + permissionSetRequests.push( + service.getPermissions(dataSource, username) + .success(function permissionsRetrieved(permissions) { + permissionSets[dataSource] = permissions; + }) + ); + }); + + // Resolve when all requests are completed + $q.all(permissionSetRequests) + .then( + + // All requests completed successfully + function allPermissionsRetrieved() { + deferred.resolve(permissionSets); + }, + + // At least one request failed + function permissionRetrievalFailed(e) { + deferred.reject(e); + } + + ); + + return deferred.promise; + + }; + /** * Makes a request to the REST API to add permissions for a given user, * returning a promise that can be used for processing the results of the