Merge pull request #254 from glyptodon/management-ui-regressions

GUAC-586: Fix regressions and clean up management UI
This commit is contained in:
James Muehlner
2015-09-03 16:38:49 -07:00
13 changed files with 288 additions and 176 deletions

View File

@@ -69,8 +69,7 @@ public class UserService extends ModeledDirectoryObjectService<ModeledUser, User
* creation. * creation.
*/ */
private static final ObjectPermission.Type[] IMPLICIT_USER_PERMISSIONS = { private static final ObjectPermission.Type[] IMPLICIT_USER_PERMISSIONS = {
ObjectPermission.Type.READ, ObjectPermission.Type.READ
ObjectPermission.Type.UPDATE
}; };
/** /**

View File

@@ -91,6 +91,11 @@ public class ConnectionService {
// Pull the current user DN from the LDAP connection // Pull the current user DN from the LDAP connection
String userDN = ldapConnection.getAuthenticationDN(); String userDN = ldapConnection.getAuthenticationDN();
// getConnections() will only be called after a connection has been
// authenticated (via non-anonymous bind), thus userDN cannot
// possibly be null
assert(userDN != null);
// Find all Guacamole connections for the given user // Find all Guacamole connections for the given user
LDAPSearchResults results = ldapConnection.search( LDAPSearchResults results = ldapConnection.search(
confService.getConfigurationBaseDN(), confService.getConfigurationBaseDN(),

View File

@@ -206,7 +206,7 @@ public class BasicFileAuthenticationProvider extends SimpleAuthenticationProvide
return null; return null;
// Validate and return info for given user and pass // Validate and return info for given user and pass
Authorization auth = getUserMapping().getAuthorization(credentials.getUsername()); Authorization auth = userMapping.getAuthorization(credentials.getUsername());
if (auth != null && auth.validate(credentials.getUsername(), credentials.getPassword())) if (auth != null && auth.validate(credentials.getUsername(), credentials.getPassword()))
return auth.getConfigurations(); return auth.getConfigurations();

View File

@@ -79,7 +79,7 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
* *
* @type String * @type String
*/ */
var dataSource = $routeParams.dataSource; var selectedDataSource = $routeParams.dataSource;
/** /**
* The username of the user being edited. * The username of the user being edited.
@@ -89,14 +89,13 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
var username = $routeParams.id; var username = $routeParams.id;
/** /**
* Whether the user being modified actually exists. If the user does not * All user accounts associated with the same username as the account being
* yet exist, a different REST service call must be made to create that * created or edited, as a map of data source identifier to the User object
* user rather than update an existing user. If the user has not yet been * within that data source.
* loaded, this will be null.
* *
* @type Boolean * @type Object.<String, User>
*/ */
var userExists = null; $scope.users = null;
/** /**
* The user being modified. * The user being modified.
@@ -122,10 +121,11 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
$scope.rootGroups = null; $scope.rootGroups = null;
/** /**
* All permissions associated with the current user, or null if the user's * A map of data source identifiers to the set of all permissions
* permissions have not yet been loaded. * 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.<String, PermissionSet>
*/ */
$scope.permissions = null; $scope.permissions = null;
@@ -155,7 +155,7 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
*/ */
$scope.isLoaded = function isLoaded() { $scope.isLoaded = function isLoaded() {
return $scope.user !== null return $scope.users !== null
&& $scope.permissionFlags !== null && $scope.permissionFlags !== null
&& $scope.rootGroups !== null && $scope.rootGroups !== null
&& $scope.permissions !== 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 * 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} * @returns {Boolean}
* true if the current user can change attributes associated with the * true if the current user can change attributes associated with the
* user being edited, false otherwise. * user being edited, false otherwise.
*/ */
$scope.canChangeAttributes = function canChangeAttributes() { $scope.canChangeAttributes = function canChangeAttributes(dataSource) {
// Do not check if permissions are not yet loaded // Do not check if permissions are not yet loaded
if (!$scope.permissions) if (!$scope.permissions)
return false; return false;
// Use currently-selected data source if unspecified
dataSource = dataSource || selectedDataSource;
// Attributes can always be set if we are creating the user // Attributes can always be set if we are creating the user
if (!userExists) if (!$scope.userExists(dataSource))
return true; return true;
// The administrator can always change attributes // The administrator can always change attributes
if (PermissionSet.hasSystemPermission($scope.permissions, if (PermissionSet.hasSystemPermission($scope.permissions[dataSource],
PermissionSet.SystemPermissionType.ADMINISTER)) PermissionSet.SystemPermissionType.ADMINISTER))
return true; return true;
// Otherwise, can change attributes if we have permission to update this user // 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); PermissionSet.ObjectPermissionType.UPDATE, username);
}; };
/** /**
* Returns whether the current user can change permissions of any kind * 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} * @returns {Boolean}
* true if the current user can grant or revoke permissions of any kind * true if the current user can grant or revoke permissions of any kind
* which are associated with the user being edited, false otherwise. * 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 // Do not check if permissions are not yet loaded
if (!$scope.permissions) if (!$scope.permissions)
return false; return false;
// Use currently-selected data source if unspecified
dataSource = dataSource || selectedDataSource;
// Permissions can always be set if we are creating the user // Permissions can always be set if we are creating the user
if (!userExists) if (!$scope.userExists(dataSource))
return true; return true;
// The administrator can always modify permissions // The administrator can always modify permissions
if (PermissionSet.hasSystemPermission($scope.permissions, if (PermissionSet.hasSystemPermission($scope.permissions[dataSource],
PermissionSet.SystemPermissionType.ADMINISTER)) PermissionSet.SystemPermissionType.ADMINISTER))
return true; return true;
// Otherwise, can only modify permissions if we have explicit // Otherwise, can only modify permissions if we have explicit
// ADMINISTER permission // ADMINISTER permission
return PermissionSet.hasUserPermission($scope.permissions, return PermissionSet.hasUserPermission($scope.permissions[dataSource],
PermissionSet.ObjectPermissionType.ADMINISTER, username); PermissionSet.ObjectPermissionType.ADMINISTER, username);
}; };
/** /**
* Returns whether the current user can change the system permissions * 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} * @returns {Boolean}
* true if the current user can grant or revoke system permissions to * true if the current user can grant or revoke system permissions to
* the user being edited, false otherwise. * the user being edited, false otherwise.
*/ */
$scope.canChangeSystemPermissions = function canChangeSystemPermissions() { $scope.canChangeSystemPermissions = function canChangeSystemPermissions(dataSource) {
// Do not check if permissions are not yet loaded // Do not check if permissions are not yet loaded
if (!$scope.permissions) if (!$scope.permissions)
return false; return false;
// Use currently-selected data source if unspecified
dataSource = dataSource || selectedDataSource;
// Only the administrator can modify system permissions // Only the administrator can modify system permissions
return PermissionSet.hasSystemPermission($scope.permissions, return PermissionSet.hasSystemPermission($scope.permissions[dataSource],
PermissionSet.SystemPermissionType.ADMINISTER); PermissionSet.SystemPermissionType.ADMINISTER);
}; };
/** /**
* Returns whether the current user can save the user being edited. Saving * Returns whether the current user can save the user being edited within
* will create or update that user depending on whether the user already * the given data source. Saving will create or update that user depending
* exists. * 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} * @returns {Boolean}
* true if the current user can save changes to the user being edited, * true if the current user can save changes to the user being edited,
* false otherwise. * false otherwise.
*/ */
$scope.canSaveUser = function canSaveUser() { $scope.canSaveUser = function canSaveUser(dataSource) {
// Do not check if permissions are not yet loaded // Do not check if permissions are not yet loaded
if (!$scope.permissions) if (!$scope.permissions)
return false; return false;
// Use currently-selected data source if unspecified
dataSource = dataSource || selectedDataSource;
// The administrator can always save users // The administrator can always save users
if (PermissionSet.hasSystemPermission($scope.permissions, if (PermissionSet.hasSystemPermission($scope.permissions[dataSource],
PermissionSet.SystemPermissionType.ADMINISTER)) PermissionSet.SystemPermissionType.ADMINISTER))
return true; return true;
// If user does not exist, can only save if we have permission to create users // If user does not exist, can only save if we have permission to create users
if (!userExists) if (!$scope.userExists(dataSource))
return PermissionSet.hasSystemPermission($scope.permissions, return PermissionSet.hasSystemPermission($scope.permissions[dataSource],
PermissionSet.SystemPermissionType.CREATE_USER); PermissionSet.SystemPermissionType.CREATE_USER);
// Otherwise, can only save if we have permission to update this 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); 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} * @returns {Boolean}
* true if the current user can delete the user being edited, false * true if the current user can delete the user being edited, false
* otherwise. * otherwise.
*/ */
$scope.canDeleteUser = function canDeleteUser() { $scope.canDeleteUser = function canDeleteUser(dataSource) {
// Do not check if permissions are not yet loaded // Do not check if permissions are not yet loaded
if (!$scope.permissions) if (!$scope.permissions)
return false; return false;
// Use currently-selected data source if unspecified
dataSource = dataSource || selectedDataSource;
// Can't delete what doesn't exist // Can't delete what doesn't exist
if (!userExists) if (!$scope.userExists(dataSource))
return false; return false;
// The administrator can always delete users // The administrator can always delete users
if (PermissionSet.hasSystemPermission($scope.permissions, if (PermissionSet.hasSystemPermission($scope.permissions[dataSource],
PermissionSet.SystemPermissionType.ADMINISTER)) PermissionSet.SystemPermissionType.ADMINISTER))
return true; return true;
// Otherwise, require explicit DELETE permission on the user // Otherwise, require explicit DELETE permission on the user
return PermissionSet.hasUserPermission($scope.permissions, return PermissionSet.hasUserPermission($scope.permissions[dataSource],
PermissionSet.ObjectPermissionType.DELETE, username); PermissionSet.ObjectPermissionType.DELETE, username);
}; };
/** /**
* Returns whether the user being edited is read-only, and thus cannot be * Returns whether the user being edited within the given data source is
* modified by the current user. * 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} * @returns {Boolean}
* true if the user being edited is actually read-only and cannot be * true if the user being edited is actually read-only and cannot be
* edited at all, false otherwise. * edited at all, false otherwise.
*/ */
$scope.isReadOnly = function isReadOnly() { $scope.isReadOnly = function isReadOnly(dataSource) {
return !$scope.canSaveUser();
// 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 // Pull user attribute schema
schemaService.getUserAttributes(dataSource).success(function attributesReceived(attributes) { schemaService.getUserAttributes(selectedDataSource).success(function attributesReceived(attributes) {
$scope.attributes = attributes; $scope.attributes = attributes;
}); });
@@ -323,38 +428,19 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
.then(function usersReceived(users) { .then(function usersReceived(users) {
// Get user for currently-selected data source // 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 // Create skeleton user if user does not exist
if (!$scope.user) { if (!$scope.user)
userExists = false;
$scope.user = new User({ $scope.user = new User({
'username' : username '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 // Pull user permissions
permissionService.getPermissions(dataSource, username).success(function gotPermissions(permissions) { permissionService.getPermissions(selectedDataSource, username).success(function gotPermissions(permissions) {
$scope.permissionFlags = PermissionFlagSet.fromPermissionSet(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 // Retrieve all connections for which we have ADMINISTER permission
dataSourceService.apply( dataSourceService.apply(
connectionGroupService.getConnectionGroupTree, connectionGroupService.getConnectionGroupTree,
[dataSource], [selectedDataSource],
ConnectionGroup.ROOT_IDENTIFIER, ConnectionGroup.ROOT_IDENTIFIER,
[PermissionSet.ObjectPermissionType.ADMINISTER] [PermissionSet.ObjectPermissionType.ADMINISTER]
) )
@@ -375,8 +461,12 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
}); });
// Query the user's permissions for the current user // Query the user's permissions for the current user
permissionService.getPermissions(dataSource, currentUsername) dataSourceService.apply(
.success(function permissionsReceived(permissions) { permissionService.getPermissions,
dataSources,
currentUsername
)
.then(function permissionsReceived(permissions) {
$scope.permissions = 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 // Save or create the user, depending on whether the user exists
var saveUserPromise; var saveUserPromise;
if (userExists) if ($scope.userExists(selectedDataSource))
saveUserPromise = userService.saveUser(dataSource, $scope.user); saveUserPromise = userService.saveUser(selectedDataSource, $scope.user);
else else
saveUserPromise = userService.createUser(dataSource, $scope.user); saveUserPromise = userService.createUser(selectedDataSource, $scope.user);
saveUserPromise.success(function savedUser() { saveUserPromise.success(function savedUser() {
// Upon success, save any changed permissions // 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() { .success(function patchedUserPermissions() {
$location.path('/settings/users'); $location.path('/settings/users');
}) })
@@ -786,7 +876,7 @@ angular.module('manage').controller('manageUserController', ['$scope', '$injecto
var deleteUserImmediately = function deleteUserImmediately() { var deleteUserImmediately = function deleteUserImmediately() {
// Delete the user // Delete the user
userService.deleteUser(dataSource, $scope.user) userService.deleteUser(selectedDataSource, $scope.user)
.success(function deletedUser() { .success(function deletedUser() {
$location.path('/settings/users'); $location.path('/settings/users');
}) })

View File

@@ -28,14 +28,16 @@
text-transform: none; text-transform: none;
} }
.manage-user .page-tabs .page-list li.unlinked a[href], .manage-user .page-tabs .page-list li.read-only a[href],
.manage-user .page-tabs .page-list li.linked 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; padding-right: 2.5em;
position: relative; position: relative;
} }
.manage-user .page-tabs .page-list li.unlinked a[href]:before, .manage-user .page-tabs .page-list li.read-only a[href]:before,
.manage-user .page-tabs .page-list li.linked 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: ' '; content: ' ';
position: absolute; position: absolute;
right: 0; right: 0;
@@ -47,6 +49,10 @@
background-position: center; 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 { .manage-user .page-tabs .page-list li.unlinked a[href]:before {
background-image: url('images/plus.png'); background-image: url('images/plus.png');
} }
@@ -63,3 +69,14 @@
.manage-user .page-tabs .page-list li.linked a[href]:before { .manage-user .page-tabs .page-list li.linked a[href]:before {
background-image: url('images/checkmark.png'); 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;
}

View File

@@ -91,13 +91,13 @@ THE SOFTWARE.
</div> </div>
</div> </div>
</div> <!-- Form action buttons -->
<div class="action-buttons">
<button ng-show="canSaveUser()" ng-click="saveUser()">{{'MANAGE_USER.ACTION_SAVE' | translate}}</button>
<button ng-click="cancel()">{{'MANAGE_USER.ACTION_CANCEL' | translate}}</button>
<button ng-show="canDeleteUser()" ng-click="deleteUser()" class="danger">{{'MANAGE_USER.ACTION_DELETE' | translate}}</button>
</div>
<!-- Form action buttons -->
<div class="action-buttons">
<button ng-show="canSaveUser()" ng-click="saveUser()">{{'MANAGE_USER.ACTION_SAVE' | translate}}</button>
<button ng-click="cancel()">{{'MANAGE_USER.ACTION_CANCEL' | translate}}</button>
<button ng-show="canDeleteUser()" ng-click="deleteUser()" class="danger">{{'MANAGE_USER.ACTION_DELETE' | translate}}</button>
</div> </div>
</div> </div>

View File

@@ -138,7 +138,7 @@ angular.module('navigation').directive('guacPageList', [function guacPageList()
name : name, name : name,
url : isCurrentPage ? currentURL : page.url, url : isCurrentPage ? currentURL : page.url,
className : page.className, className : page.className,
weight : page.weight || weight weight : page.weight || (weight + i)
}); });
} }

View File

@@ -53,6 +53,14 @@ angular.module('navigation').factory('userPageService', ['$injector',
url : '/' 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. * Returns an appropriate home page for the current user.
* *
@@ -78,9 +86,12 @@ angular.module('navigation').factory('userPageService', ['$injector',
var connections = rootGroup.childConnections || []; var connections = rootGroup.childConnections || [];
var connectionGroups = rootGroup.childConnectionGroups || []; 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 // If exactly one connection or balancing group is available, use
// that as the home page // that as the home page
if (homePage === null && connections.length + connectionGroups.length === 1) { if (homePage === null && totalRootObjects === 1) {
var connection = connections[0]; var connection = connections[0];
var connectionGroup = connectionGroups[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 // Otherwise, a connection or balancing group cannot serve as the
// home page // home page
else { else if (totalRootObjects >= 1) {
homePage = null; homePage = null;
break; break;
} }
@@ -173,8 +184,14 @@ angular.module('navigation').factory('userPageService', ['$injector',
var canManageSessions = []; var canManageSessions = [];
// Inspect the contents of each provided permission set // 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); permissions = angular.copy(permissions);
// Ignore permission to update root group // Ignore permission to update root group

View File

@@ -191,6 +191,10 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet()
*/ */
var hasPermission = function hasPermission(permMap, type, identifier) { 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 no identifier given, search ignoring the identifier
if (!identifier) if (!identifier)
return containsPermission(permMap, type); return containsPermission(permMap, type);
@@ -303,6 +307,7 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet()
* true if the permission is present (granted), false otherwise. * true if the permission is present (granted), false otherwise.
*/ */
PermissionSet.hasSystemPermission = function hasSystemPermission(permSet, type) { PermissionSet.hasSystemPermission = function hasSystemPermission(permSet, type) {
if (!permSet.systemPermissions) return false;
return permSet.systemPermissions.indexOf(type) !== -1; return permSet.systemPermissions.indexOf(type) !== -1;
}; };
@@ -324,6 +329,8 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet()
*/ */
PermissionSet.addSystemPermission = function addSystemPermission(permSet, type) { PermissionSet.addSystemPermission = function addSystemPermission(permSet, type) {
permSet.systemPermissions = permSet.systemPermissions || [];
// Add permission, if it doesn't already exist // Add permission, if it doesn't already exist
if (permSet.systemPermissions.indexOf(type) === -1) { if (permSet.systemPermissions.indexOf(type) === -1) {
permSet.systemPermissions.push(type); permSet.systemPermissions.push(type);
@@ -352,6 +359,8 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet()
*/ */
PermissionSet.removeSystemPermission = function removeSystemPermission(permSet, type) { PermissionSet.removeSystemPermission = function removeSystemPermission(permSet, type) {
permSet.systemPermissions = permSet.systemPermissions || [];
// Remove permission, if it exists // Remove permission, if it exists
var permLocation = permSet.systemPermissions.indexOf(type); var permLocation = permSet.systemPermissions.indexOf(type);
if (permLocation !== -1) { if (permLocation !== -1) {
@@ -463,6 +472,7 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet()
* already present in the given permission set. * already present in the given permission set.
*/ */
PermissionSet.addConnectionPermission = function addConnectionPermission(permSet, type, identifier) { PermissionSet.addConnectionPermission = function addConnectionPermission(permSet, type, identifier) {
permSet.connectionPermissions = permSet.connectionPermissions || {};
return addObjectPermission(permSet.connectionPermissions, type, identifier); return addObjectPermission(permSet.connectionPermissions, type, identifier);
}; };
@@ -486,6 +496,7 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet()
* present in the given permission set. * present in the given permission set.
*/ */
PermissionSet.removeConnectionPermission = function removeConnectionPermission(permSet, type, identifier) { PermissionSet.removeConnectionPermission = function removeConnectionPermission(permSet, type, identifier) {
permSet.connectionPermissions = permSet.connectionPermissions || {};
return removeObjectPermission(permSet.connectionPermissions, type, identifier); return removeObjectPermission(permSet.connectionPermissions, type, identifier);
}; };
@@ -511,6 +522,7 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet()
* already present in the given permission set. * already present in the given permission set.
*/ */
PermissionSet.addConnectionGroupPermission = function addConnectionGroupPermission(permSet, type, identifier) { PermissionSet.addConnectionGroupPermission = function addConnectionGroupPermission(permSet, type, identifier) {
permSet.connectionGroupPermissions = permSet.connectionGroupPermissions || {};
return addObjectPermission(permSet.connectionGroupPermissions, type, identifier); return addObjectPermission(permSet.connectionGroupPermissions, type, identifier);
}; };
@@ -535,6 +547,7 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet()
* present in the given permission set. * present in the given permission set.
*/ */
PermissionSet.removeConnectionGroupPermission = function removeConnectionGroupPermission(permSet, type, identifier) { PermissionSet.removeConnectionGroupPermission = function removeConnectionGroupPermission(permSet, type, identifier) {
permSet.connectionGroupPermissions = permSet.connectionGroupPermissions || {};
return removeObjectPermission(permSet.connectionGroupPermissions, type, identifier); return removeObjectPermission(permSet.connectionGroupPermissions, type, identifier);
}; };
@@ -560,6 +573,7 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet()
* already present in the given permission set. * already present in the given permission set.
*/ */
PermissionSet.addActiveConnectionPermission = function addActiveConnectionPermission(permSet, type, identifier) { PermissionSet.addActiveConnectionPermission = function addActiveConnectionPermission(permSet, type, identifier) {
permSet.activeConnectionPermissions = permSet.activeConnectionPermissions || {};
return addObjectPermission(permSet.activeConnectionPermissions, type, identifier); return addObjectPermission(permSet.activeConnectionPermissions, type, identifier);
}; };
@@ -584,6 +598,7 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet()
* present in the given permission set. * present in the given permission set.
*/ */
PermissionSet.removeActiveConnectionPermission = function removeActiveConnectionPermission(permSet, type, identifier) { PermissionSet.removeActiveConnectionPermission = function removeActiveConnectionPermission(permSet, type, identifier) {
permSet.activeConnectionPermissions = permSet.activeConnectionPermissions || {};
return removeObjectPermission(permSet.activeConnectionPermissions, type, identifier); return removeObjectPermission(permSet.activeConnectionPermissions, type, identifier);
}; };
@@ -607,6 +622,7 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet()
* already present in the given permission set. * already present in the given permission set.
*/ */
PermissionSet.addUserPermission = function addUserPermission(permSet, type, identifier) { PermissionSet.addUserPermission = function addUserPermission(permSet, type, identifier) {
permSet.userPermissions = permSet.userPermissions || {};
return addObjectPermission(permSet.userPermissions, type, identifier); return addObjectPermission(permSet.userPermissions, type, identifier);
}; };
@@ -630,6 +646,7 @@ angular.module('rest').factory('PermissionSet', [function definePermissionSet()
* present in the given permission set. * present in the given permission set.
*/ */
PermissionSet.removeUserPermission = function removeUserPermission(permSet, type, identifier) { PermissionSet.removeUserPermission = function removeUserPermission(permSet, type, identifier) {
permSet.userPermissions = permSet.userPermissions || {};
return removeObjectPermission(permSet.userPermissions, type, identifier); return removeObjectPermission(permSet.userPermissions, type, identifier);
}; };

View File

@@ -41,6 +41,7 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe
var PermissionSet = $injector.get('PermissionSet'); var PermissionSet = $injector.get('PermissionSet');
// Required services // Required services
var $location = $injector.get('$location');
var $routeParams = $injector.get('$routeParams'); var $routeParams = $injector.get('$routeParams');
var authenticationService = $injector.get('authenticationService'); var authenticationService = $injector.get('authenticationService');
var connectionGroupService = $injector.get('connectionGroupService'); var connectionGroupService = $injector.get('connectionGroupService');
@@ -81,36 +82,11 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe
*/ */
$scope.rootGroups = null; $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 * All permissions associated with the current user, or null if the
* user's permissions have not yet been loaded. * user's permissions have not yet been loaded.
* *
* @type Object.<String, PermissionSet> * @type PermissionSet
*/ */
$scope.permissions = null; $scope.permissions = null;
@@ -130,11 +106,11 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe
/** /**
* Returns whether the current user can create new connections * Returns whether the current user can create new connections
* within at least one data source. * within the current data source.
* *
* @return {Boolean} * @return {Boolean}
* true if the current user can create new connections within * 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() { $scope.canCreateConnections = function canCreateConnections() {
@@ -142,18 +118,10 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe
if (!$scope.permissions) if (!$scope.permissions)
return false; return false;
// For each data source // Can create connections if adminstrator or have explicit permission
for (var dataSource in $scope.permissions) { if (PermissionSet.hasSystemPermission($scope.permissions, PermissionSet.SystemPermissionType.ADMINISTER)
|| PermissionSet.hasSystemPermission($scope.permissions, PermissionSet.SystemPermissionType.CREATE_CONNECTION))
// Retrieve corresponding permission set return true;
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;
}
// No data sources allow connection creation // No data sources allow connection creation
return false; return false;
@@ -162,11 +130,11 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe
/** /**
* Returns whether the current user can create new connection * Returns whether the current user can create new connection
* groups within at least one data source. * groups within the current data source.
* *
* @return {Boolean} * @return {Boolean}
* true if the current user can create new connection groups * 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() { $scope.canCreateConnectionGroups = function canCreateConnectionGroups() {
@@ -174,18 +142,10 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe
if (!$scope.permissions) if (!$scope.permissions)
return false; return false;
// For each data source // Can create connections groups if adminstrator or have explicit permission
for (var dataSource in $scope.permissions) { if (PermissionSet.hasSystemPermission($scope.permissions, PermissionSet.SystemPermissionType.ADMINISTER)
|| PermissionSet.hasSystemPermission($scope.permissions, PermissionSet.SystemPermissionType.CREATE_CONNECTION_GROUP))
// Retrieve corresponding permission set return true;
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;
}
// No data sources allow connection group creation // No data sources allow connection group creation
return false; return false;
@@ -195,14 +155,14 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe
/** /**
* Returns whether the current user can create new connections or * Returns whether the current user can create new connections or
* connection groups or make changes to existing 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 * connection management interface as a whole is useless if this
* function returns false. * function returns false.
* *
* @return {Boolean} * @return {Boolean}
* true if the current user can create new connections/groups * true if the current user can create new connections/groups
* or make changes to existing connections/groups within at * or make changes to existing connections/groups within the
* least one data source, false otherwise. * current data source, false otherwise.
*/ */
$scope.canManageConnections = function canManageConnections() { $scope.canManageConnections = function canManageConnections() {
@@ -214,26 +174,15 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe
if ($scope.canCreateConnections() || $scope.canCreateConnectionGroups()) if ($scope.canCreateConnections() || $scope.canCreateConnectionGroups())
return true; return true;
// Ignore permission to update root group // Can manage connections if granted explicit update or delete
PermissionSet.removeConnectionGroupPermission(permissions, PermissionSet.ObjectPermissionType.UPDATE, ConnectionGroup.ROOT_IDENTIFIER); if (PermissionSet.hasConnectionPermission($scope.permissions, PermissionSet.ObjectPermissionType.UPDATE)
|| PermissionSet.hasConnectionPermission($scope.permissions, PermissionSet.ObjectPermissionType.DELETE))
return true;
// For each data source // Can manage connections groups if granted explicit update or delete
for (var dataSource in $scope.permissions) { if (PermissionSet.hasConnectionGroupPermission($scope.permissions, PermissionSet.ObjectPermissionType.UPDATE)
|| PermissionSet.hasConnectionGroupPermission($scope.permissions, PermissionSet.ObjectPermissionType.DELETE))
// Retrieve corresponding permission set return true;
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;
}
// No data sources allow management of connections or groups // No data sources allow management of connections or groups
return false; return false;
@@ -241,13 +190,19 @@ angular.module('settings').directive('guacSettingsConnections', [function guacSe
}; };
// Retrieve current permissions // Retrieve current permissions
dataSourceService.apply( permissionService.getPermissions($scope.dataSource, currentUsername)
permissionService.getPermissions, .success(function permissionsRetrieved(permissions) {
[$scope.dataSource],
currentUsername // Store retrieved permissions
)
.then(function permissionsRetrieved(permissions) {
$scope.permissions = 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 // Retrieve all connections for which we have UPDATE or DELETE permission

View File

@@ -194,7 +194,11 @@ angular.module('settings').directive('guacSettingsUsers', [function guacSettings
}; };
// Retrieve current permissions // Retrieve current permissions
dataSourceService.apply(permissionService.getPermissions, dataSources, currentUsername) dataSourceService.apply(
permissionService.getPermissions,
dataSources,
currentUsername
)
.then(function permissionsRetrieved(permissions) { .then(function permissionsRetrieved(permissions) {
// Store retrieved permissions // Store retrieved permissions
@@ -230,6 +234,12 @@ angular.module('settings').directive('guacSettingsUsers', [function guacSettings
if (addedUsers[user.username]) if (addedUsers[user.username])
return; 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 // Add user to overall list
addedUsers[user.username] = user; addedUsers[user.username] = user;
$scope.manageableUsers.push(new ManageableUser ({ $scope.manageableUsers.push(new ManageableUser ({
@@ -249,7 +259,9 @@ angular.module('settings').directive('guacSettingsUsers', [function guacSettings
* username specified. * username specified.
*/ */
$scope.newUser = function newUser() { $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));
}; };
}] }]

View File

@@ -28,11 +28,11 @@
<div class="action-buttons"> <div class="action-buttons">
<a class="add-connection button" <a class="add-connection button"
ng-show="canCreateConnections" ng-show="canCreateConnections()"
href="#/manage/{{dataSource}}/connections/">{{'SETTINGS_CONNECTIONS.ACTION_NEW_CONNECTION' | translate}}</a> href="#/manage/{{dataSource}}/connections/">{{'SETTINGS_CONNECTIONS.ACTION_NEW_CONNECTION' | translate}}</a>
<a class="add-connection-group button" <a class="add-connection-group button"
ng-show="canCreateConnectionGroups" ng-show="canCreateConnectionGroups()"
href="#/manage/{{dataSource}}/connectionGroups/">{{'SETTINGS_CONNECTIONS.ACTION_NEW_CONNECTION_GROUP' | translate}}</a> href="#/manage/{{dataSource}}/connectionGroups/">{{'SETTINGS_CONNECTIONS.ACTION_NEW_CONNECTION_GROUP' | translate}}</a>
</div> </div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 B