diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserService.java index 74b00c21d..6f609b2b8 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserService.java @@ -69,8 +69,7 @@ public class UserService extends ModeledDirectoryObjectService */ - var userExists = null; + $scope.users = null; /** * The user being modified. @@ -122,10 +121,11 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto $scope.rootGroups = null; /** - * All permissions associated with the current user, or null if the user's - * permissions have not yet been loaded. + * A map of data source identifiers to the set of all permissions + * associated with the current user under that data source, or null if the + * user's permissions have not yet been loaded. * - * @type PermissionSet + * @type Object. */ $scope.permissions = null; @@ -155,7 +155,7 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto */ $scope.isLoaded = function isLoaded() { - return $scope.user !== null + return $scope.users !== null && $scope.permissionFlags !== null && $scope.rootGroups !== null && $scope.permissions !== null @@ -163,158 +163,263 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto }; + /** + * Returns whether the user being edited already exists within the data + * source specified. + * + * @param {String} [dataSource] + * The identifier of the data source to check. If omitted, this will + * default to the currently-selected data source. + * + * @returns {Boolean} + * true if the user being edited already exists, false otherwise. + */ + $scope.userExists = function userExists(dataSource) { + + // Do not check if users are not yet loaded + if (!$scope.users) + return false; + + // Use currently-selected data source if unspecified + dataSource = dataSource || selectedDataSource; + + // Account exists only if it was successfully retrieved + return (dataSource in $scope.users); + + }; + /** * Returns whether the current user can change attributes associated with - * the user being edited. + * the user being edited within the given data source. + * + * @param {String} [dataSource] + * The identifier of the data source to check. If omitted, this will + * default to the currently-selected data source. * * @returns {Boolean} * true if the current user can change attributes associated with the * user being edited, false otherwise. */ - $scope.canChangeAttributes = function canChangeAttributes() { + $scope.canChangeAttributes = function canChangeAttributes(dataSource) { // Do not check if permissions are not yet loaded if (!$scope.permissions) return false; + // Use currently-selected data source if unspecified + dataSource = dataSource || selectedDataSource; + // Attributes can always be set if we are creating the user - if (!userExists) + if (!$scope.userExists(dataSource)) return true; // The administrator can always change attributes - if (PermissionSet.hasSystemPermission($scope.permissions, + if (PermissionSet.hasSystemPermission($scope.permissions[dataSource], PermissionSet.SystemPermissionType.ADMINISTER)) return true; // Otherwise, can change attributes if we have permission to update this user - return PermissionSet.hasUserPermission($scope.permissions, + return PermissionSet.hasUserPermission($scope.permissions[dataSource], PermissionSet.ObjectPermissionType.UPDATE, username); }; /** * Returns whether the current user can change permissions of any kind - * which are associated with the user being edited. + * which are associated with the user being edited within the given data + * source. + * + * @param {String} [dataSource] + * The identifier of the data source to check. If omitted, this will + * default to the currently-selected data source. * * @returns {Boolean} * true if the current user can grant or revoke permissions of any kind * which are associated with the user being edited, false otherwise. */ - $scope.canChangePermissions = function canChangePermissions() { + $scope.canChangePermissions = function canChangePermissions(dataSource) { // Do not check if permissions are not yet loaded if (!$scope.permissions) return false; + // Use currently-selected data source if unspecified + dataSource = dataSource || selectedDataSource; + // Permissions can always be set if we are creating the user - if (!userExists) + if (!$scope.userExists(dataSource)) return true; // The administrator can always modify permissions - if (PermissionSet.hasSystemPermission($scope.permissions, + if (PermissionSet.hasSystemPermission($scope.permissions[dataSource], PermissionSet.SystemPermissionType.ADMINISTER)) return true; // Otherwise, can only modify permissions if we have explicit // ADMINISTER permission - return PermissionSet.hasUserPermission($scope.permissions, + return PermissionSet.hasUserPermission($scope.permissions[dataSource], PermissionSet.ObjectPermissionType.ADMINISTER, username); }; /** * Returns whether the current user can change the system permissions - * granted to the user being edited. + * granted to the user being edited within the given data source. + * + * @param {String} [dataSource] + * The identifier of the data source to check. If omitted, this will + * default to the currently-selected data source. * * @returns {Boolean} * true if the current user can grant or revoke system permissions to * the user being edited, false otherwise. */ - $scope.canChangeSystemPermissions = function canChangeSystemPermissions() { + $scope.canChangeSystemPermissions = function canChangeSystemPermissions(dataSource) { // Do not check if permissions are not yet loaded if (!$scope.permissions) return false; + // Use currently-selected data source if unspecified + dataSource = dataSource || selectedDataSource; + // Only the administrator can modify system permissions - return PermissionSet.hasSystemPermission($scope.permissions, + return PermissionSet.hasSystemPermission($scope.permissions[dataSource], PermissionSet.SystemPermissionType.ADMINISTER); }; /** - * Returns whether the current user can save the user being edited. Saving - * will create or update that user depending on whether the user already - * exists. + * Returns whether the current user can save the user being edited within + * the given data source. Saving will create or update that user depending + * on whether the user already exists. + * + * @param {String} [dataSource] + * The identifier of the data source to check. If omitted, this will + * default to the currently-selected data source. * * @returns {Boolean} * true if the current user can save changes to the user being edited, * false otherwise. */ - $scope.canSaveUser = function canSaveUser() { + $scope.canSaveUser = function canSaveUser(dataSource) { // Do not check if permissions are not yet loaded if (!$scope.permissions) return false; + // Use currently-selected data source if unspecified + dataSource = dataSource || selectedDataSource; + // The administrator can always save users - if (PermissionSet.hasSystemPermission($scope.permissions, + if (PermissionSet.hasSystemPermission($scope.permissions[dataSource], PermissionSet.SystemPermissionType.ADMINISTER)) return true; // If user does not exist, can only save if we have permission to create users - if (!userExists) - return PermissionSet.hasSystemPermission($scope.permissions, + if (!$scope.userExists(dataSource)) + return PermissionSet.hasSystemPermission($scope.permissions[dataSource], PermissionSet.SystemPermissionType.CREATE_USER); // Otherwise, can only save if we have permission to update this user - return PermissionSet.hasUserPermission($scope.permissions, + return PermissionSet.hasUserPermission($scope.permissions[dataSource], PermissionSet.ObjectPermissionType.UPDATE, username); }; /** - * Returns whether the current user can delete the user being edited. + * Returns whether the current user can delete the user being edited from + * the given data source. + * + * @param {String} [dataSource] + * The identifier of the data source to check. If omitted, this will + * default to the currently-selected data source. * * @returns {Boolean} * true if the current user can delete the user being edited, false * otherwise. */ - $scope.canDeleteUser = function canDeleteUser() { + $scope.canDeleteUser = function canDeleteUser(dataSource) { // Do not check if permissions are not yet loaded if (!$scope.permissions) return false; + // Use currently-selected data source if unspecified + dataSource = dataSource || selectedDataSource; + // Can't delete what doesn't exist - if (!userExists) + if (!$scope.userExists(dataSource)) return false; // The administrator can always delete users - if (PermissionSet.hasSystemPermission($scope.permissions, + if (PermissionSet.hasSystemPermission($scope.permissions[dataSource], PermissionSet.SystemPermissionType.ADMINISTER)) return true; // Otherwise, require explicit DELETE permission on the user - return PermissionSet.hasUserPermission($scope.permissions, + return PermissionSet.hasUserPermission($scope.permissions[dataSource], PermissionSet.ObjectPermissionType.DELETE, username); }; /** - * Returns whether the user being edited is read-only, and thus cannot be - * modified by the current user. + * Returns whether the user being edited within the given data source is + * read-only, and thus cannot be modified by the current user. + * + * @param {String} [dataSource] + * The identifier of the data source to check. If omitted, this will + * default to the currently-selected data source. * * @returns {Boolean} * true if the user being edited is actually read-only and cannot be * edited at all, false otherwise. */ - $scope.isReadOnly = function isReadOnly() { - return !$scope.canSaveUser(); + $scope.isReadOnly = function isReadOnly(dataSource) { + + // Use currently-selected data source if unspecified + dataSource = dataSource || selectedDataSource; + + // User is read-only if they cannot be saved + return !$scope.canSaveUser(dataSource); + }; + // Update visible account pages whenever available users/permissions changes + $scope.$watchGroup(['users', 'permissions'], function updateAccountPages() { + + // Generate pages for each applicable data source + $scope.accountPages = []; + angular.forEach(dataSources, function addAccountPage(dataSource) { + + // Determine whether data source contains this user + var linked = $scope.userExists(dataSource); + var readOnly = $scope.isReadOnly(dataSource); + + // Account is not relevant if it does not exist and cannot be + // created + if (!linked && readOnly) + return; + + // Determine class name based on read-only / linked status + var className; + if (readOnly) className = 'read-only'; + else if (linked) className = 'linked'; + else className = 'unlinked'; + + // Add page entry + $scope.accountPages.push(new PageDefinition({ + name : translationStringService.canonicalize('DATA_SOURCE_' + dataSource) + '.NAME', + url : '/manage/' + encodeURIComponent(dataSource) + '/users/' + encodeURIComponent(username), + className : className + })); + + }); + + }); + // Pull user attribute schema - schemaService.getUserAttributes(dataSource).success(function attributesReceived(attributes) { + schemaService.getUserAttributes(selectedDataSource).success(function attributesReceived(attributes) { $scope.attributes = attributes; }); @@ -323,38 +428,19 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto .then(function usersReceived(users) { // Get user for currently-selected data source - $scope.user = users[dataSource]; + $scope.users = users; + $scope.user = users[selectedDataSource]; // Create skeleton user if user does not exist - if (!$scope.user) { - userExists = false; + if (!$scope.user) $scope.user = new User({ 'username' : username }); - } - else - userExists = true; - - // Generate pages for each applicable data source - $scope.accountPages = []; - angular.forEach(dataSources, function addAccountPage(dataSource) { - - // Determine whether data source contains this user - var linked = dataSource in users; - - // Add page entry - $scope.accountPages.push(new PageDefinition({ - name : translationStringService.canonicalize('DATA_SOURCE_' + dataSource) + '.NAME', - url : '/manage/' + encodeURIComponent(dataSource) + '/users/' + encodeURIComponent(username), - className : linked ? 'linked' : 'unlinked' - })); - - }); }); // Pull user permissions - permissionService.getPermissions(dataSource, username).success(function gotPermissions(permissions) { + permissionService.getPermissions(selectedDataSource, username).success(function gotPermissions(permissions) { $scope.permissionFlags = PermissionFlagSet.fromPermissionSet(permissions); }) @@ -366,7 +452,7 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto // Retrieve all connections for which we have ADMINISTER permission dataSourceService.apply( connectionGroupService.getConnectionGroupTree, - [dataSource], + [selectedDataSource], ConnectionGroup.ROOT_IDENTIFIER, [PermissionSet.ObjectPermissionType.ADMINISTER] ) @@ -375,8 +461,12 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto }); // Query the user's permissions for the current user - permissionService.getPermissions(dataSource, currentUsername) - .success(function permissionsReceived(permissions) { + dataSourceService.apply( + permissionService.getPermissions, + dataSources, + currentUsername + ) + .then(function permissionsReceived(permissions) { $scope.permissions = permissions; }); @@ -716,15 +806,15 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto // Save or create the user, depending on whether the user exists var saveUserPromise; - if (userExists) - saveUserPromise = userService.saveUser(dataSource, $scope.user); + if ($scope.userExists(selectedDataSource)) + saveUserPromise = userService.saveUser(selectedDataSource, $scope.user); else - saveUserPromise = userService.createUser(dataSource, $scope.user); + saveUserPromise = userService.createUser(selectedDataSource, $scope.user); saveUserPromise.success(function savedUser() { // Upon success, save any changed permissions - permissionService.patchPermissions(dataSource, $scope.user.username, permissionsAdded, permissionsRemoved) + permissionService.patchPermissions(selectedDataSource, $scope.user.username, permissionsAdded, permissionsRemoved) .success(function patchedUserPermissions() { $location.path('/settings/users'); }) @@ -786,7 +876,7 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto var deleteUserImmediately = function deleteUserImmediately() { // Delete the user - userService.deleteUser(dataSource, $scope.user) + userService.deleteUser(selectedDataSource, $scope.user) .success(function deletedUser() { $location.path('/settings/users'); }) diff --git a/guacamole/src/main/webapp/app/manage/styles/manage-user.css b/guacamole/src/main/webapp/app/manage/styles/manage-user.css index 7d6f077db..3445b6d5c 100644 --- a/guacamole/src/main/webapp/app/manage/styles/manage-user.css +++ b/guacamole/src/main/webapp/app/manage/styles/manage-user.css @@ -28,14 +28,16 @@ text-transform: none; } -.manage-user .page-tabs .page-list li.unlinked a[href], -.manage-user .page-tabs .page-list li.linked a[href] { +.manage-user .page-tabs .page-list li.read-only a[href], +.manage-user .page-tabs .page-list li.unlinked a[href], +.manage-user .page-tabs .page-list li.linked a[href] { padding-right: 2.5em; position: relative; } -.manage-user .page-tabs .page-list li.unlinked a[href]:before, -.manage-user .page-tabs .page-list li.linked a[href]:before { +.manage-user .page-tabs .page-list li.read-only a[href]:before, +.manage-user .page-tabs .page-list li.unlinked a[href]:before, +.manage-user .page-tabs .page-list li.linked a[href]:before { content: ' '; position: absolute; right: 0; @@ -47,6 +49,10 @@ background-position: center; } +.manage-user .page-tabs .page-list li.read-only a[href]:before { + background-image: url('images/lock.png'); +} + .manage-user .page-tabs .page-list li.unlinked a[href]:before { background-image: url('images/plus.png'); } @@ -63,3 +69,14 @@ .manage-user .page-tabs .page-list li.linked a[href]:before { background-image: url('images/checkmark.png'); } + +.manage-user .notice.read-only { + + background: #FDA; + border: 1px solid rgba(0, 0, 0, 0.125); + border-radius: 0.25em; + + text-align: center; + padding: 1em; + +} \ No newline at end of file diff --git a/guacamole/src/main/webapp/app/manage/templates/manageUser.html b/guacamole/src/main/webapp/app/manage/templates/manageUser.html index 71a6d93cf..ab93683f6 100644 --- a/guacamole/src/main/webapp/app/manage/templates/manageUser.html +++ b/guacamole/src/main/webapp/app/manage/templates/manageUser.html @@ -91,13 +91,13 @@ THE SOFTWARE. - + +
+ + + +
- -
- - -
diff --git a/guacamole/src/main/webapp/app/navigation/directives/guacPageList.js b/guacamole/src/main/webapp/app/navigation/directives/guacPageList.js index ef2b05e61..cc4d8fb13 100644 --- a/guacamole/src/main/webapp/app/navigation/directives/guacPageList.js +++ b/guacamole/src/main/webapp/app/navigation/directives/guacPageList.js @@ -138,7 +138,7 @@ angular.module('navigation').directive('guacPageList', [function guacPageList() name : name, url : isCurrentPage ? currentURL : page.url, className : page.className, - weight : page.weight || weight + weight : page.weight || (weight + i) }); } diff --git a/guacamole/src/main/webapp/app/navigation/services/userPageService.js b/guacamole/src/main/webapp/app/navigation/services/userPageService.js index 27878ceb8..d42b0381a 100644 --- a/guacamole/src/main/webapp/app/navigation/services/userPageService.js +++ b/guacamole/src/main/webapp/app/navigation/services/userPageService.js @@ -53,6 +53,14 @@ angular.module('navigation').factory('userPageService', ['$injector', url : '/' }); + /** + * The identifiers of all data sources currently available to the + * authenticated user. + * + * @type String[] + */ + var dataSources = authenticationService.getAvailableDataSources(); + /** * Returns an appropriate home page for the current user. * @@ -78,9 +86,12 @@ angular.module('navigation').factory('userPageService', ['$injector', var connections = rootGroup.childConnections || []; var connectionGroups = rootGroup.childConnectionGroups || []; + // Calculate total number of root-level objects + var totalRootObjects = connections.length + connectionGroups.length; + // If exactly one connection or balancing group is available, use // that as the home page - if (homePage === null && connections.length + connectionGroups.length === 1) { + if (homePage === null && totalRootObjects === 1) { var connection = connections[0]; var connectionGroup = connectionGroups[0]; @@ -116,7 +127,7 @@ angular.module('navigation').factory('userPageService', ['$injector', // Otherwise, a connection or balancing group cannot serve as the // home page - else { + else if (totalRootObjects >= 1) { homePage = null; break; } @@ -173,8 +184,14 @@ angular.module('navigation').factory('userPageService', ['$injector', var canManageSessions = []; // Inspect the contents of each provided permission set - angular.forEach(permissionSets, function inspectPermissions(permissions, dataSource) { + angular.forEach(dataSources, function inspectPermissions(dataSource) { + // Get permissions for current data source, skipping if non-existent + var permissions = permissionSets[dataSource]; + if (!permissions) + return; + + // Do not modify original object permissions = angular.copy(permissions); // Ignore permission to update root group diff --git a/guacamole/src/main/webapp/app/rest/types/PermissionSet.js b/guacamole/src/main/webapp/app/rest/types/PermissionSet.js index 7f61f3d02..c7e92378f 100644 --- a/guacamole/src/main/webapp/app/rest/types/PermissionSet.js +++ b/guacamole/src/main/webapp/app/rest/types/PermissionSet.js @@ -191,6 +191,10 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet() */ var hasPermission = function hasPermission(permMap, type, identifier) { + // No permission if no permission map at all + if (!permMap) + return false; + // If no identifier given, search ignoring the identifier if (!identifier) return containsPermission(permMap, type); @@ -303,6 +307,7 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet() * true if the permission is present (granted), false otherwise. */ PermissionSet.hasSystemPermission = function hasSystemPermission(permSet, type) { + if (!permSet.systemPermissions) return false; return permSet.systemPermissions.indexOf(type) !== -1; }; @@ -324,6 +329,8 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet() */ PermissionSet.addSystemPermission = function addSystemPermission(permSet, type) { + permSet.systemPermissions = permSet.systemPermissions || []; + // Add permission, if it doesn't already exist if (permSet.systemPermissions.indexOf(type) === -1) { permSet.systemPermissions.push(type); @@ -352,6 +359,8 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet() */ PermissionSet.removeSystemPermission = function removeSystemPermission(permSet, type) { + permSet.systemPermissions = permSet.systemPermissions || []; + // Remove permission, if it exists var permLocation = permSet.systemPermissions.indexOf(type); if (permLocation !== -1) { @@ -463,6 +472,7 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet() * already present in the given permission set. */ PermissionSet.addConnectionPermission = function addConnectionPermission(permSet, type, identifier) { + permSet.connectionPermissions = permSet.connectionPermissions || {}; return addObjectPermission(permSet.connectionPermissions, type, identifier); }; @@ -486,6 +496,7 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet() * present in the given permission set. */ PermissionSet.removeConnectionPermission = function removeConnectionPermission(permSet, type, identifier) { + permSet.connectionPermissions = permSet.connectionPermissions || {}; return removeObjectPermission(permSet.connectionPermissions, type, identifier); }; @@ -511,6 +522,7 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet() * already present in the given permission set. */ PermissionSet.addConnectionGroupPermission = function addConnectionGroupPermission(permSet, type, identifier) { + permSet.connectionGroupPermissions = permSet.connectionGroupPermissions || {}; return addObjectPermission(permSet.connectionGroupPermissions, type, identifier); }; @@ -535,6 +547,7 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet() * present in the given permission set. */ PermissionSet.removeConnectionGroupPermission = function removeConnectionGroupPermission(permSet, type, identifier) { + permSet.connectionGroupPermissions = permSet.connectionGroupPermissions || {}; return removeObjectPermission(permSet.connectionGroupPermissions, type, identifier); }; @@ -560,6 +573,7 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet() * already present in the given permission set. */ PermissionSet.addActiveConnectionPermission = function addActiveConnectionPermission(permSet, type, identifier) { + permSet.activeConnectionPermissions = permSet.activeConnectionPermissions || {}; return addObjectPermission(permSet.activeConnectionPermissions, type, identifier); }; @@ -584,6 +598,7 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet() * present in the given permission set. */ PermissionSet.removeActiveConnectionPermission = function removeActiveConnectionPermission(permSet, type, identifier) { + permSet.activeConnectionPermissions = permSet.activeConnectionPermissions || {}; return removeObjectPermission(permSet.activeConnectionPermissions, type, identifier); }; @@ -607,6 +622,7 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet() * already present in the given permission set. */ PermissionSet.addUserPermission = function addUserPermission(permSet, type, identifier) { + permSet.userPermissions = permSet.userPermissions || {}; return addObjectPermission(permSet.userPermissions, type, identifier); }; @@ -630,6 +646,7 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet() * present in the given permission set. */ PermissionSet.removeUserPermission = function removeUserPermission(permSet, type, identifier) { + permSet.userPermissions = permSet.userPermissions || {}; return removeObjectPermission(permSet.userPermissions, type, identifier); }; diff --git a/guacamole/src/main/webapp/app/settings/directives/guacSettingsConnections.js b/guacamole/src/main/webapp/app/settings/directives/guacSettingsConnections.js index fe0449fe2..d088cbc31 100644 --- a/guacamole/src/main/webapp/app/settings/directives/guacSettingsConnections.js +++ b/guacamole/src/main/webapp/app/settings/directives/guacSettingsConnections.js @@ -41,6 +41,7 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe var PermissionSet = $injector.get('PermissionSet'); // Required services + var $location = $injector.get('$location'); var $routeParams = $injector.get('$routeParams'); var authenticationService = $injector.get('authenticationService'); var connectionGroupService = $injector.get('connectionGroupService'); @@ -81,36 +82,11 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe */ $scope.rootGroups = null; - /** - * Whether the current user can manage connections. If the current - * permissions have not yet been loaded, this will be null. - * - * @type Boolean - */ - $scope.canManageConnections = null; - - /** - * Whether the current user can create new connections. If the - * current permissions have not yet been loaded, this will be null. - * - * @type Boolean - */ - $scope.canCreateConnections = null; - - /** - * Whether the current user can create new connection groups. If - * the current permissions have not yet been loaded, this will be - * null. - * - * @type Boolean - */ - $scope.canCreateConnectionGroups = null; - /** * All permissions associated with the current user, or null if the * user's permissions have not yet been loaded. * - * @type Object. + * @type PermissionSet */ $scope.permissions = null; @@ -130,11 +106,11 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe /** * Returns whether the current user can create new connections - * within at least one data source. + * within the current data source. * * @return {Boolean} * true if the current user can create new connections within - * at least one data source, false otherwise. + * the current data source, false otherwise. */ $scope.canCreateConnections = function canCreateConnections() { @@ -142,18 +118,10 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe if (!$scope.permissions) return false; - // For each data source - for (var dataSource in $scope.permissions) { - - // Retrieve corresponding permission set - var permissionSet = $scope.permissions[dataSource]; - - // Can create connections if adminstrator or have explicit permission - if (PermissionSet.hasSystemPermission(permissionSet, PermissionSet.SystemPermissionType.ADMINISTER) - || PermissionSet.hasSystemPermission(permissionSet, PermissionSet.SystemPermissionType.CREATE_CONNECTION)) - return true; - - } + // Can create connections if adminstrator or have explicit permission + if (PermissionSet.hasSystemPermission($scope.permissions, PermissionSet.SystemPermissionType.ADMINISTER) + || PermissionSet.hasSystemPermission($scope.permissions, PermissionSet.SystemPermissionType.CREATE_CONNECTION)) + return true; // No data sources allow connection creation return false; @@ -162,11 +130,11 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe /** * Returns whether the current user can create new connection - * groups within at least one data source. + * groups within the current data source. * * @return {Boolean} * true if the current user can create new connection groups - * within at least one data source, false otherwise. + * within the current data source, false otherwise. */ $scope.canCreateConnectionGroups = function canCreateConnectionGroups() { @@ -174,18 +142,10 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe if (!$scope.permissions) return false; - // For each data source - for (var dataSource in $scope.permissions) { - - // Retrieve corresponding permission set - var permissionSet = $scope.permissions[dataSource]; - - // Can create connections groups if adminstrator or have explicit permission - if (PermissionSet.hasSystemPermission(permissionSet, PermissionSet.SystemPermissionType.ADMINISTER) - || PermissionSet.hasSystemPermission(permissionSet, PermissionSet.SystemPermissionType.CREATE_CONNECTION_GROUP)) - return true; - - } + // Can create connections groups if adminstrator or have explicit permission + if (PermissionSet.hasSystemPermission($scope.permissions, PermissionSet.SystemPermissionType.ADMINISTER) + || PermissionSet.hasSystemPermission($scope.permissions, PermissionSet.SystemPermissionType.CREATE_CONNECTION_GROUP)) + return true; // No data sources allow connection group creation return false; @@ -195,14 +155,14 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe /** * Returns whether the current user can create new connections or * connection groups or make changes to existing connections or - * connection groups within at least one data source. The + * connection groups within the current data source. The * connection management interface as a whole is useless if this * function returns false. * * @return {Boolean} * true if the current user can create new connections/groups - * or make changes to existing connections/groups within at - * least one data source, false otherwise. + * or make changes to existing connections/groups within the + * current data source, false otherwise. */ $scope.canManageConnections = function canManageConnections() { @@ -214,26 +174,15 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe if ($scope.canCreateConnections() || $scope.canCreateConnectionGroups()) return true; - // Ignore permission to update root group - PermissionSet.removeConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE, ConnectionGroup.ROOT_IDENTIFIER); + // Can manage connections if granted explicit update or delete + if (PermissionSet.hasConnectionPermission($scope.permissions, PermissionSet.ObjectPermissionType.UPDATE) + || PermissionSet.hasConnectionPermission($scope.permissions, PermissionSet.ObjectPermissionType.DELETE)) + return true; - // For each data source - for (var dataSource in $scope.permissions) { - - // Retrieve corresponding permission set - var permissionSet = $scope.permissions[dataSource]; - - // Can manage connections if granted explicit update or delete - if (PermissionSet.hasConnectionPermission(permissionSet, PermissionSet.ObjectPermissionType.UPDATE) - || PermissionSet.hasConnectionPermission(permissionSet, PermissionSet.ObjectPermissionType.DELETE)) - return true; - - // Can manage connections groups if granted explicit update or delete - if (PermissionSet.hasConnectionGroupPermission(permissionSet, PermissionSet.ObjectPermissionType.UPDATE) - || PermissionSet.hasConnectionGroupPermission(permissionSet, PermissionSet.ObjectPermissionType.DELETE)) - return true; - - } + // Can manage connections groups if granted explicit update or delete + if (PermissionSet.hasConnectionGroupPermission($scope.permissions, PermissionSet.ObjectPermissionType.UPDATE) + || PermissionSet.hasConnectionGroupPermission($scope.permissions, PermissionSet.ObjectPermissionType.DELETE)) + return true; // No data sources allow management of connections or groups return false; @@ -241,13 +190,19 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe }; // Retrieve current permissions - dataSourceService.apply( - permissionService.getPermissions, - [$scope.dataSource], - currentUsername - ) - .then(function permissionsRetrieved(permissions) { + permissionService.getPermissions($scope.dataSource, currentUsername) + .success(function permissionsRetrieved(permissions) { + + // Store retrieved permissions $scope.permissions = permissions; + + // Ignore permission to update root group + PermissionSet.removeConnectionGroupPermission($scope.permissions, PermissionSet.ObjectPermissionType.UPDATE, ConnectionGroup.ROOT_IDENTIFIER); + + // Return to home if there's nothing to do here + if (!$scope.canManageConnections()) + $location.path('/'); + }); // Retrieve all connections for which we have UPDATE or DELETE permission diff --git a/guacamole/src/main/webapp/app/settings/directives/guacSettingsUsers.js b/guacamole/src/main/webapp/app/settings/directives/guacSettingsUsers.js index af52ee3bf..5802145fa 100644 --- a/guacamole/src/main/webapp/app/settings/directives/guacSettingsUsers.js +++ b/guacamole/src/main/webapp/app/settings/directives/guacSettingsUsers.js @@ -194,7 +194,11 @@ angular.module('settings').directive('guacSettingsUsers', [function guacSettings }; // Retrieve current permissions - dataSourceService.apply(permissionService.getPermissions, dataSources, currentUsername) + dataSourceService.apply( + permissionService.getPermissions, + dataSources, + currentUsername + ) .then(function permissionsRetrieved(permissions) { // Store retrieved permissions @@ -230,6 +234,12 @@ angular.module('settings').directive('guacSettingsUsers', [function guacSettings if (addedUsers[user.username]) return; + // Link to default creation data source if we cannot manage this user + if (!PermissionSet.hasSystemPermission(permissions[dataSource], PermissionSet.ObjectPermissionType.ADMINISTER) + && !PermissionSet.hasUserPermission(permissions[dataSource], PermissionSet.ObjectPermissionType.UPDATE, user.username) + && !PermissionSet.hasUserPermission(permissions[dataSource], PermissionSet.ObjectPermissionType.DELETE, user.username)) + dataSource = getDefaultDataSource(); + // Add user to overall list addedUsers[user.username] = user; $scope.manageableUsers.push(new ManageableUser ({ @@ -249,7 +259,9 @@ angular.module('settings').directive('guacSettingsUsers', [function guacSettings * username specified. */ $scope.newUser = function newUser() { - $location.url('/manage/' + encodeURIComponent(getDefaultDataSource()) + '/users/' + encodeURIComponent($scope.newUsername)); + var username = $scope.newUsername.trim(); + if (username) + $location.url('/manage/' + encodeURIComponent(getDefaultDataSource()) + '/users/' + encodeURIComponent(username)); }; }] diff --git a/guacamole/src/main/webapp/app/settings/templates/settingsConnections.html b/guacamole/src/main/webapp/app/settings/templates/settingsConnections.html index 0f9b618df..efecf6f8a 100644 --- a/guacamole/src/main/webapp/app/settings/templates/settingsConnections.html +++ b/guacamole/src/main/webapp/app/settings/templates/settingsConnections.html @@ -28,11 +28,11 @@ diff --git a/guacamole/src/main/webapp/images/lock.png b/guacamole/src/main/webapp/images/lock.png new file mode 100644 index 000000000..399d51182 Binary files /dev/null and b/guacamole/src/main/webapp/images/lock.png differ