GUACAMOLE-1656: Simplify, clean up, and improve documentation of KSM code.

This commit is contained in:
James Muehlner
2022-08-29 22:08:31 +00:00
parent dfc7e6dd90
commit 8a7bde8e9c
14 changed files with 216 additions and 284 deletions

View File

@@ -68,7 +68,7 @@ angular.module('settings').directive('guacSettingsPreferences', [function guacSe
callback : function acknowledgeCallback() {
userService.getUser(dataSource, username)
.then(user => $scope.user = user)
.then(guacNotification.showStatus(false))
.then(() => guacNotification.showStatus(false));
}
};
@@ -101,17 +101,6 @@ angular.module('settings').directive('guacSettingsPreferences', [function guacSe
*/
$scope.preferences = preferenceService.preferences;
/**
* All available user attributes, as a mapping of form name to form
* object. The form object contains a name, as well as a Map of fields.
*
* The Map type is used here to maintain form/name uniqueness, as well as
* insertion order, to ensure a consistent UI experience.
*
* @type Map<String, Object>
*/
$scope.attributeMap = new Map();
/**
* All available user attributes. This is only the set of attribute
* definitions, organized as logical groupings of attributes, not attribute
@@ -263,61 +252,10 @@ angular.module('settings').directive('guacSettingsPreferences', [function guacSe
$scope.user = user;
})
// Get all datasources that are available for this user
authenticationService.getAvailableDataSources().forEach(function loadAttributesForDataSource(dataSource) {
// Fetch all user attribute forms defined for the datasource
schemaService.getUserPreferenceAttributes(dataSource).then(function saveAttributes(attributes) {
// Iterate through all attribute forms
attributes.forEach(function addAttribute(attributeForm) {
// If the form with the retrieved name already exists
if ($scope.attributeMap.has(attributeForm.name)) {
const existingFields = $scope.attributeMap.get(attributeForm.name).fields;
// Add each field to the existing list for this form
attributeForm.fields.forEach(function addAllFieldsToExistingMap(field) {
existingFields.set(field.name, field);
})
}
else {
// Create a new entry for the form
$scope.attributeMap.set(attributeForm.name, {
name: attributeForm.name,
// With the field array from the API converted into a Map
fields: attributeForm.fields.reduce(
function addFieldToMap(currentFieldMap, field) {
currentFieldMap.set(field.name, field);
return currentFieldMap;
}, new Map()
)
})
}
});
// Re-generate the attributes array every time
$scope.attributes = Array.of(...$scope.attributeMap.values()).map(function convertFieldsToArray(formObject) {
// Convert each temporary form object to a Form type
return new Form({
name: formObject.name,
// Convert the field map to a simple array of fields
fields: Array.of(...formObject.fields.values())
})
});
});
// Fetch all user preference attribute forms defined
schemaService.getUserPreferenceAttributes(dataSource).then(function saveAttributes(attributes) {
$scope.attributes = attributes;
});
}]
};
}]);

View File

@@ -943,7 +943,7 @@
"HELP_UPDATE_PASSWORD" : "If you wish to change your password, enter your current password and the desired new password below, and click \"Update Password\". The change will take effect immediately.",
"INFO_PASSWORD_CHANGED" : "Password changed.",
"INFO_PREFERENCE_ATTRIBUTES_CHANGED" : "User attributes saved.",
"INFO_PREFERENCE_ATTRIBUTES_CHANGED" : "User settings saved.",
"NAME_INPUT_METHOD_NONE" : "@:CLIENT.NAME_INPUT_METHOD_NONE",
"NAME_INPUT_METHOD_OSK" : "@:CLIENT.NAME_INPUT_METHOD_OSK",

View File

@@ -77,6 +77,18 @@ module.exports = {
]
},
optimization: {
minimizer: [
// Minify using Google Closure Compiler
new ClosureWebpackPlugin({ mode: 'STANDARD' }, {
languageIn: 'ECMASCRIPT_2020',
languageOut: 'ECMASCRIPT5',
compilationLevel: 'SIMPLE'
}),
new CssMinimizerPlugin()
],
splitChunks: {
cacheGroups: {

View File

@@ -89,7 +89,7 @@ public class SchemaResource {
*/
@GET
@Path("userPreferenceAttributes")
public Collection<Form> getUserAttrigetUserPreferenceAttributesbutes()
public Collection<Form> getUserPreferenceAttributes()
throws GuacamoleException {
// Retrieve all possible user preference attributes

View File

@@ -59,9 +59,22 @@ public class UserObjectTranslator
public void filterExternalObject(UserContext userContext, APIUser object)
throws GuacamoleException {
// Filter object attributes by defined schema
object.setAttributes(filterAttributes(userContext.getUserAttributes(),
object.getAttributes()));
// If a user is editing themselves ...
if (object.getUsername().equals(userContext.self().getIdentifier())) {
// ... they may only edit preference attributes
object.setAttributes(filterAttributes(userContext.getUserPreferenceAttributes(),
object.getAttributes()));
}
else {
// In all other cases, filter object attributes by defined schema
object.setAttributes(filterAttributes(userContext.getUserAttributes(),
object.getAttributes()));
}
}

View File

@@ -22,10 +22,6 @@ package org.apache.guacamole.rest.user;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import java.util.Iterator;
import java.util.Set;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
@@ -150,50 +146,14 @@ public class UserResource
@Override
public void updateObject(APIUser modifiedObject) throws GuacamoleException {
// A user may not use this endpoint to update their password
User currentUser = userContext.self();
// A user may not use this endpoint to modify themself, except in the case
// that they are modifying one of the user attributes explicitly exposed
// in the user preferences form
if (currentUser.getIdentifier().equals(modifiedObject.getUsername())) {
// A user may not use this endpoint to update their password
if (currentUser.getPassword() != null)
throw new GuacamoleSecurityException(
"Permission denied. The password update endpoint must"
+ " be used to change the current user's password.");
// All attributes exposed in the preferences forms
Set<String> preferenceAttributes = (
userContext.getUserPreferenceAttributes().stream()
.flatMap(form -> form.getFields().stream().map(
field -> field.getName())))
.collect(Collectors.toSet());
// Go through every attribute value and check if it's changed
Iterator<String> keyIterator = modifiedObject.getAttributes().keySet().iterator();
while(keyIterator.hasNext()) {
String key = keyIterator.next();
String newValue = modifiedObject.getAttributes().get(key);
// If it's not a preference attribute, editing is not allowed
if (!preferenceAttributes.contains(key)) {
String currentValue = currentUser.getAttributes().get(key);
// If the value of the attribute has been modified
if (
!(currentValue == null && newValue == null) && (
(currentValue == null && newValue != null) ||
!currentValue.equals(newValue)
)
)
throw new GuacamoleSecurityException(
"Permission denied. Only user preference attributes"
+ " can be modified for the current user.");
}
}
if (
currentUser.getIdentifier().equals(modifiedObject.getUsername())
&& modifiedObject.getPassword() != null) {
throw new GuacamoleSecurityException(
"Permission denied. The password update endpoint must"
+ " be used to change the current user's password.");
}
super.updateObject(modifiedObject);