mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 05:07:41 +00:00
GUACAMOLE-96: Add base support within JDBC auth for storage of arbitrary attributes from other extensions.
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.guacamole.auth.jdbc.base;
|
||||
|
||||
import java.util.AbstractCollection;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Map of arbitrary attribute name/value pairs which can alternatively be
|
||||
* exposed as a collection of model objects.
|
||||
*/
|
||||
public class ArbitraryAttributeMap extends HashMap<String, String> {
|
||||
|
||||
/**
|
||||
* Creates a new ArbitraryAttributeMap containing the name/value pairs
|
||||
* within the given collection of model objects.
|
||||
*
|
||||
* @param models
|
||||
* The model objects of all attributes which should be stored in the
|
||||
* new map as name/value pairs.
|
||||
*
|
||||
* @return
|
||||
* A new ArbitraryAttributeMap containing the name/value pairs within
|
||||
* the given collection of model objects.
|
||||
*/
|
||||
public static ArbitraryAttributeMap fromModelCollection(Collection<ArbitraryAttributeModel> models) {
|
||||
|
||||
// Add all name/value pairs from the given collection to the map
|
||||
ArbitraryAttributeMap map = new ArbitraryAttributeMap();
|
||||
for (ArbitraryAttributeModel model : models)
|
||||
map.put(model.getName(), model.getValue());
|
||||
|
||||
return map;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a collection of model objects which mirrors the contents of this
|
||||
* ArbitraryAttributeMap. Each name/value pair within the map is reflected
|
||||
* by a corresponding model object within the returned collection. Removing
|
||||
* a model object from the collection removes the corresponding name/value
|
||||
* pair from the map. Adding a new model object to the collection adds a
|
||||
* corresponding name/value pair to the map. Changes to a model object
|
||||
* within the collection are NOT reflected on the map, however.
|
||||
*
|
||||
* @return
|
||||
* A collection of model objects which mirrors the contents of this
|
||||
* ArbitraryAttributeMap.
|
||||
*/
|
||||
public Collection<ArbitraryAttributeModel> toModelCollection() {
|
||||
return new AbstractCollection<ArbitraryAttributeModel>() {
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
ArbitraryAttributeMap.this.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
|
||||
// The Collection view of an ArbitraryAttributeMap can contain
|
||||
// only ArbitraryAttributeModel objects
|
||||
if (!(o instanceof ArbitraryAttributeModel))
|
||||
return false;
|
||||
|
||||
// The attribute should be removed only if the value matches
|
||||
ArbitraryAttributeModel model = (ArbitraryAttributeModel) o;
|
||||
return ArbitraryAttributeMap.this.remove(model.getName(),
|
||||
model.getValue());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(ArbitraryAttributeModel e) {
|
||||
|
||||
String newValue = e.getValue();
|
||||
String oldValue = put(e.getName(), newValue);
|
||||
|
||||
// If null value is being added, collection changed only if
|
||||
// old value was non-null
|
||||
if (newValue == null)
|
||||
return oldValue != null;
|
||||
|
||||
// Collection changed if value changed
|
||||
return !newValue.equals(oldValue);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
|
||||
// The Collection view of an ArbitraryAttributeMap can contain
|
||||
// only ArbitraryAttributeModel objects
|
||||
if (!(o instanceof ArbitraryAttributeModel))
|
||||
return false;
|
||||
|
||||
// No need to check the value of the attribute if the attribute
|
||||
// is not even present
|
||||
ArbitraryAttributeModel model = (ArbitraryAttributeModel) o;
|
||||
String value = get(model.getName());
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
// The name/value pair is present only if the value matches
|
||||
return value.equals(model.getValue());
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ArbitraryAttributeModel> iterator() {
|
||||
|
||||
// Get iterator over all string name/value entries
|
||||
final Iterator<Entry<String, String>> iterator = entrySet().iterator();
|
||||
|
||||
// Dynamically translate each string name/value entry into a
|
||||
// corresponding attribute model object as iteration continues
|
||||
return new Iterator<ArbitraryAttributeModel>() {
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return iterator.hasNext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArbitraryAttributeModel next() {
|
||||
Entry<String, String> entry = iterator.next();
|
||||
return new ArbitraryAttributeModel(entry.getKey(),
|
||||
entry.getValue());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return ArbitraryAttributeMap.this.size();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
package org.apache.guacamole.auth.jdbc.base;
|
||||
|
||||
/**
|
||||
* A single attribute name/value pair belonging to a object which implements
|
||||
* the Attributes interface, such as a Connection or User. Attributes stored
|
||||
* as raw name/value pairs are the attributes which are given to the database
|
||||
* authentication extension for storage by other extensions. Attributes which
|
||||
* are directly supported by the database authentication extension have defined
|
||||
* columns and properties with proper types, constraints, etc.
|
||||
*/
|
||||
public class ArbitraryAttributeModel {
|
||||
|
||||
/**
|
||||
* The name of the attribute.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The value the attribute is set to.
|
||||
*/
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* Creates a new ArbitraryAttributeModel with its name and value both set
|
||||
* to null.
|
||||
*/
|
||||
public ArbitraryAttributeModel() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ArbitraryAttributeModel with its name and value
|
||||
* initialized to the given values.
|
||||
*
|
||||
* @param name
|
||||
* The name of the attribute.
|
||||
*
|
||||
* @param value
|
||||
* The value the attribute is set to.
|
||||
*/
|
||||
public ArbitraryAttributeModel(String name, String value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this attribute.
|
||||
*
|
||||
* @return
|
||||
* The name of this attribute.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of this attribute.
|
||||
*
|
||||
* @param name
|
||||
* The name of this attribute.
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this attribute.
|
||||
*
|
||||
* @return
|
||||
* The value of this attribute.
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of this attribute.
|
||||
*
|
||||
* @param value
|
||||
* The value of this attribute.
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
}
|
@@ -65,35 +65,32 @@ public abstract class ModeledDirectoryObject<ModelType extends ObjectModel>
|
||||
|
||||
@Override
|
||||
public Map<String, String> getAttributes() {
|
||||
|
||||
// If no arbitrary attributes are defined, just return an empty map
|
||||
Map<String, String> arbitraryAttributes = getModel().getArbitraryAttributes();
|
||||
if (arbitraryAttributes == null)
|
||||
return new HashMap<String, String>();
|
||||
|
||||
// Otherwise include any defined arbitrary attributes
|
||||
return new HashMap<String, String>(arbitraryAttributes);
|
||||
|
||||
return new HashMap<String, String>(getModel().getArbitraryAttributeMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttributes(Map<String, String> attributes) {
|
||||
|
||||
ArbitraryAttributeMap arbitraryAttributes = getModel().getArbitraryAttributeMap();
|
||||
|
||||
// Get set of all supported attribute names
|
||||
Set<String> supportedAttributes = getSupportedAttributeNames();
|
||||
|
||||
// Initialize model with empty map if no such map is already present
|
||||
Map<String, String> arbitraryAttributes = getModel().getArbitraryAttributes();
|
||||
if (arbitraryAttributes == null) {
|
||||
arbitraryAttributes = new HashMap<String, String>();
|
||||
getModel().setArbitraryAttributes(arbitraryAttributes);
|
||||
}
|
||||
|
||||
// Store remaining attributes only if not directly mapped to model
|
||||
for (Map.Entry<String, String> attribute : attributes.entrySet()) {
|
||||
|
||||
String name = attribute.getKey();
|
||||
if (!supportedAttributes.contains(name))
|
||||
arbitraryAttributes.put(name, attribute.getValue());
|
||||
String value = attribute.getValue();
|
||||
|
||||
// Handle null attributes as explicit removal of that attribute,
|
||||
// as the underlying model cannot store null attribute values
|
||||
if (!supportedAttributes.contains(name)) {
|
||||
if (value == null)
|
||||
arbitraryAttributes.remove(name);
|
||||
else
|
||||
arbitraryAttributes.put(name, value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -132,5 +132,28 @@ public interface ModeledDirectoryObjectMapper<ModelType> {
|
||||
* The number of rows updated.
|
||||
*/
|
||||
int update(@Param("object") ModelType object);
|
||||
|
||||
|
||||
/**
|
||||
* Deletes any arbitrary attributes currently associated with the given
|
||||
* object in the database.
|
||||
*
|
||||
* @param object
|
||||
* The object whose arbitrary attributes should be deleted.
|
||||
*
|
||||
* @return
|
||||
* The number of rows deleted.
|
||||
*/
|
||||
int deleteAttributes(@Param("object") ModelType object);
|
||||
|
||||
/**
|
||||
* Inserts all arbitrary attributes associated with the given object.
|
||||
*
|
||||
* @param object
|
||||
* The object whose arbitrary attributes should be inserted.
|
||||
*
|
||||
* @return
|
||||
* The number of rows inserted.
|
||||
*/
|
||||
int insertAttributes(@Param("object") ModelType object);
|
||||
|
||||
}
|
||||
|
@@ -32,6 +32,7 @@ import org.apache.guacamole.auth.jdbc.user.UserModel;
|
||||
import org.apache.guacamole.net.auth.Identifiable;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermission;
|
||||
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
|
||||
import org.mybatis.guice.transactional.Transactional;
|
||||
|
||||
/**
|
||||
* Service which provides convenience methods for creating, retrieving, and
|
||||
@@ -446,6 +447,7 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public InternalType createObject(ModeledAuthenticatedUser user, ExternalType object)
|
||||
throws GuacamoleException {
|
||||
|
||||
@@ -461,6 +463,10 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
|
||||
// Add implicit permissions
|
||||
getPermissionMapper().insert(getImplicitPermissions(user, model));
|
||||
|
||||
// Add any arbitrary attributes
|
||||
if (model.hasArbitraryAttributes())
|
||||
getObjectMapper().insertAttributes(model);
|
||||
|
||||
return getObjectInstance(user, model);
|
||||
|
||||
}
|
||||
@@ -477,6 +483,7 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void updateObject(ModeledAuthenticatedUser user, InternalType object)
|
||||
throws GuacamoleException {
|
||||
|
||||
@@ -486,6 +493,11 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
|
||||
// Update object
|
||||
getObjectMapper().update(model);
|
||||
|
||||
// Replace any existing arbitrary attributes
|
||||
getObjectMapper().deleteAttributes(model);
|
||||
if (model.hasArbitraryAttributes())
|
||||
getObjectMapper().insertAttributes(model);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -19,7 +19,7 @@
|
||||
|
||||
package org.apache.guacamole.auth.jdbc.base;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Object representation of a Guacamole object, such as a user or connection,
|
||||
@@ -41,7 +41,8 @@ public abstract class ObjectModel {
|
||||
* Map of all arbitrary attributes associated with this object but not
|
||||
* directly mapped to a particular column.
|
||||
*/
|
||||
private Map<String, String> arbitraryAttributes;
|
||||
private ArbitraryAttributeMap arbitraryAttributes =
|
||||
new ArbitraryAttributeMap();
|
||||
|
||||
/**
|
||||
* Creates a new, empty object.
|
||||
@@ -102,23 +103,47 @@ public abstract class ObjectModel {
|
||||
* with this model which do not otherwise have explicit mappings to
|
||||
* properties.
|
||||
*/
|
||||
public Map<String, String> getArbitraryAttributes() {
|
||||
public ArbitraryAttributeMap getArbitraryAttributeMap() {
|
||||
return arbitraryAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets all arbitrary attribute name/value pairs associated with this
|
||||
* model. The provided map should contain only attributes which are not
|
||||
* explicitly supported by the model, as any explicitly-supported
|
||||
* attributes should instead be mapped to corresponding properties.
|
||||
* Returns whether at least one arbitrary attribute name/value pair has
|
||||
* been associated with this object.
|
||||
*
|
||||
* @return
|
||||
* true if this object has at least one arbitrary attribute set, false
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean hasArbitraryAttributes() {
|
||||
return !arbitraryAttributes.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Collection view of the equivalent attribute model objects
|
||||
* which make up the map of arbitrary attribute name/value pairs returned
|
||||
* by getArbitraryAttributeMap(). Additions and removals on the returned
|
||||
* Collection directly affect the attribute map.
|
||||
*
|
||||
* @return
|
||||
* A Collection view of the map returned by
|
||||
* getArbitraryAttributeMap().
|
||||
*/
|
||||
public Collection<ArbitraryAttributeModel> getArbitraryAttributes() {
|
||||
return arbitraryAttributes.toModelCollection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces all arbitrary attributes associated with this object with the
|
||||
* attribute name/value pairs within the given collection of model objects.
|
||||
*
|
||||
* @param arbitraryAttributes
|
||||
* A map of attribute name/value pairs for all attributes associated
|
||||
* with this model which do not otherwise have explicit mappings to
|
||||
* properties.
|
||||
* The Collection of model objects containing the attribute name/value
|
||||
* pairs which should replace all currently-stored arbitrary attributes,
|
||||
* if any.
|
||||
*/
|
||||
public void setArbitraryAttributes(Map<String, String> arbitraryAttributes) {
|
||||
this.arbitraryAttributes = arbitraryAttributes;
|
||||
public void setArbitraryAttributes(Collection<ArbitraryAttributeModel> arbitraryAttributes) {
|
||||
this.arbitraryAttributes = ArbitraryAttributeMap.fromModelCollection(arbitraryAttributes);
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user