GUACAMOLE-96: Merge allow extensions to voluntarily store each other's data.

This commit is contained in:
Nick Couchman
2018-02-01 13:31:46 -05:00
46 changed files with 2110 additions and 169 deletions

View File

@@ -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();
}
};
}
}

View File

@@ -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;
}
}

View File

@@ -19,6 +19,11 @@
package org.apache.guacamole.auth.jdbc.base;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import org.apache.guacamole.net.auth.Attributes;
import org.apache.guacamole.net.auth.Identifiable;
/**
@@ -31,7 +36,7 @@ import org.apache.guacamole.net.auth.Identifiable;
* The type of model object that corresponds to this object.
*/
public abstract class ModeledDirectoryObject<ModelType extends ObjectModel>
extends ModeledObject<ModelType> implements Identifiable {
extends ModeledObject<ModelType> implements Identifiable, Attributes {
@Override
public String getIdentifier() {
@@ -43,4 +48,51 @@ public abstract class ModeledDirectoryObject<ModelType extends ObjectModel>
getModel().setIdentifier(identifier);
}
/**
* Returns the names of all attributes explicitly supported by this object.
* Attributes named here have associated mappings within the backing model
* object, and thus should not be included in the arbitrary attribute
* storage. Any attributes set which do not match these names, such as those
* set via other extensions, will be added to arbitrary attribute storage.
*
* @return
* A read-only Set of the names of all attributes explicitly supported
* (mapped to a property of the backing model) by this object.
*/
public Set<String> getSupportedAttributeNames() {
return Collections.<String>emptySet();
}
@Override
public Map<String, String> getAttributes() {
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();
// Store remaining attributes only if not directly mapped to model
for (Map.Entry<String, String> attribute : attributes.entrySet()) {
String name = attribute.getKey();
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);
}
}
}
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -19,6 +19,8 @@
package org.apache.guacamole.auth.jdbc.base;
import java.util.Collection;
/**
* Object representation of a Guacamole object, such as a user or connection,
* as represented in the database.
@@ -34,7 +36,14 @@ public abstract class ObjectModel {
* The unique identifier which identifies this object.
*/
private String identifier;
/**
* Map of all arbitrary attributes associated with this object but not
* directly mapped to a particular column.
*/
private ArbitraryAttributeMap arbitraryAttributes =
new ArbitraryAttributeMap();
/**
* Creates a new, empty object.
*/
@@ -82,4 +91,59 @@ public abstract class ObjectModel {
this.objectID = objectID;
}
/**
* Returns a map of attribute name/value pairs for all attributes associated
* with this model which do not have explicit mappings to actual model
* properties. All other attributes (those which are explicitly supported
* by the model) should instead be mapped to properties with corresponding
* and properly-typed columns.
*
* @return
* A map of attribute name/value pairs for all attributes associated
* with this model which do not otherwise have explicit mappings to
* properties.
*/
public ArbitraryAttributeMap getArbitraryAttributeMap() {
return arbitraryAttributes;
}
/**
* 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
* The Collection of model objects containing the attribute name/value
* pairs which should replace all currently-stored arbitrary attributes,
* if any.
*/
public void setArbitraryAttributes(Collection<ArbitraryAttributeModel> arbitraryAttributes) {
this.arbitraryAttributes = ArbitraryAttributeMap.fromModelCollection(arbitraryAttributes);
}
}

View File

@@ -25,7 +25,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -157,6 +157,21 @@ public class ModeledConnection extends ModeledChildDirectoryObject<ConnectionMod
GUACD_PARAMETERS
));
/**
* The names of all attributes which are explicitly supported by this
* extension's Connection objects.
*/
public static final Set<String> ATTRIBUTE_NAMES =
Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
GUACD_HOSTNAME_NAME,
GUACD_PORT_NAME,
GUACD_ENCRYPTION_NAME,
MAX_CONNECTIONS_NAME,
MAX_CONNECTIONS_PER_USER_NAME,
CONNECTION_WEIGHT,
FAILOVER_ONLY_NAME
)));
/**
* The environment of the Guacamole server.
*/
@@ -253,10 +268,16 @@ public class ModeledConnection extends ModeledChildDirectoryObject<ConnectionMod
return tunnelService.getActiveConnections(this).size();
}
@Override
public Set<String> getSupportedAttributeNames() {
return ATTRIBUTE_NAMES;
}
@Override
public Map<String, String> getAttributes() {
Map<String, String> attributes = new HashMap<String, String>();
// Include any defined arbitrary attributes
Map<String, String> attributes = super.getAttributes();
// Set connection limit attribute
attributes.put(MAX_CONNECTIONS_NAME, NumericField.format(getModel().getMaxConnections()));
@@ -305,6 +326,9 @@ public class ModeledConnection extends ModeledChildDirectoryObject<ConnectionMod
@Override
public void setAttributes(Map<String, String> attributes) {
// Set arbitrary attributes
super.setAttributes(attributes);
// Translate connection limit attribute
try { getModel().setMaxConnections(NumericField.parse(attributes.get(MAX_CONNECTIONS_NAME))); }
catch (NumberFormatException e) {

View File

@@ -23,7 +23,7 @@ import com.google.inject.Inject;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.guacamole.GuacamoleException;
@@ -89,6 +89,17 @@ public class ModeledConnectionGroup extends ModeledChildDirectoryObject<Connecti
CONCURRENCY_LIMITS
));
/**
* The names of all attributes which are explicitly supported by this
* extension's ConnectionGroup objects.
*/
public static final Set<String> ATTRIBUTE_NAMES =
Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
MAX_CONNECTIONS_NAME,
MAX_CONNECTIONS_PER_USER_NAME,
ENABLE_SESSION_AFFINITY
)));
/**
* The environment of the Guacamole server.
*/
@@ -156,10 +167,16 @@ public class ModeledConnectionGroup extends ModeledChildDirectoryObject<Connecti
return getModel().getConnectionGroupIdentifiers();
}
@Override
public Set<String> getSupportedAttributeNames() {
return ATTRIBUTE_NAMES;
}
@Override
public Map<String, String> getAttributes() {
Map<String, String> attributes = new HashMap<String, String>();
// Include any defined arbitrary attributes
Map<String, String> attributes = super.getAttributes();
// Set connection limit attribute
attributes.put(MAX_CONNECTIONS_NAME, NumericField.format(getModel().getMaxConnections()));
@@ -177,6 +194,9 @@ public class ModeledConnectionGroup extends ModeledChildDirectoryObject<Connecti
@Override
public void setAttributes(Map<String, String> attributes) {
// Set arbitrary attributes
super.setAttributes(attributes);
// Translate connection limit attribute
try { getModel().setMaxConnections(NumericField.parse(attributes.get(MAX_CONNECTIONS_NAME))); }
catch (NumberFormatException e) {

View File

@@ -95,14 +95,4 @@ public class ModeledSharingProfile
this.parameters = parameters;
}
@Override
public Map<String, String> getAttributes() {
return Collections.<String, String>emptyMap();
}
@Override
public void setAttributes(Map<String, String> attributes) {
// Do nothing - no attributes
}
}

View File

@@ -28,9 +28,10 @@ import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import org.apache.guacamole.auth.jdbc.base.ModeledDirectoryObject;
import org.apache.guacamole.auth.jdbc.security.PasswordEncryptionService;
@@ -144,6 +145,25 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
ACCOUNT_RESTRICTIONS
));
/**
* The names of all attributes which are explicitly supported by this
* extension's User objects.
*/
public static final Set<String> ATTRIBUTE_NAMES =
Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
User.Attribute.FULL_NAME,
User.Attribute.EMAIL_ADDRESS,
User.Attribute.ORGANIZATION,
User.Attribute.ORGANIZATIONAL_ROLE,
DISABLED_ATTRIBUTE_NAME,
EXPIRED_ATTRIBUTE_NAME,
ACCESS_WINDOW_START_ATTRIBUTE_NAME,
ACCESS_WINDOW_END_ATTRIBUTE_NAME,
VALID_FROM_ATTRIBUTE_NAME,
VALID_UNTIL_ATTRIBUTE_NAME,
TIMEZONE_ATTRIBUTE_NAME
)));
/**
* Service for managing users.
*/
@@ -547,10 +567,16 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
}
@Override
public Set<String> getSupportedAttributeNames() {
return ATTRIBUTE_NAMES;
}
@Override
public Map<String, String> getAttributes() {
Map<String, String> attributes = new HashMap<String, String>();
// Include any defined arbitrary attributes
Map<String, String> attributes = super.getAttributes();
// Always include unrestricted attributes
putUnrestrictedAttributes(attributes);
@@ -565,6 +591,9 @@ public class ModeledUser extends ModeledDirectoryObject<UserModel> implements Us
@Override
public void setAttributes(Map<String, String> attributes) {
// Set arbitrary attributes
super.setAttributes(attributes);
// Always assign unrestricted attributes
setUnrestrictedAttributes(attributes);

View File

@@ -185,6 +185,94 @@ CREATE TABLE guacamole_sharing_profile_parameter (
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of arbitrary user attributes. Each attribute is simply a name/value
-- pair associated with a user. Arbitrary attributes are defined by other
-- extensions. Attributes defined by this extension will be mapped to
-- properly-typed columns of a specific table.
--
CREATE TABLE guacamole_user_attribute (
`user_id` int(11) NOT NULL,
`attribute_name` varchar(128) NOT NULL,
`attribute_value` varchar(4096) NOT NULL,
PRIMARY KEY (user_id, attribute_name),
KEY `user_id` (`user_id`),
CONSTRAINT guacamole_user_attribute_ibfk_1
FOREIGN KEY (user_id)
REFERENCES guacamole_user (user_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of arbitrary connection attributes. Each attribute is simply a
-- name/value pair associated with a connection. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE guacamole_connection_attribute (
`connection_id` int(11) NOT NULL,
`attribute_name` varchar(128) NOT NULL,
`attribute_value` varchar(4096) NOT NULL,
PRIMARY KEY (connection_id, attribute_name),
KEY `connection_id` (`connection_id`),
CONSTRAINT guacamole_connection_attribute_ibfk_1
FOREIGN KEY (connection_id)
REFERENCES guacamole_connection (connection_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of arbitrary connection group attributes. Each attribute is simply a
-- name/value pair associated with a connection group. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE guacamole_connection_group_attribute (
`connection_group_id` int(11) NOT NULL,
`attribute_name` varchar(128) NOT NULL,
`attribute_value` varchar(4096) NOT NULL,
PRIMARY KEY (connection_group_id, attribute_name),
KEY `connection_group_id` (`connection_group_id`),
CONSTRAINT guacamole_connection_group_attribute_ibfk_1
FOREIGN KEY (connection_group_id)
REFERENCES guacamole_connection_group (connection_group_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of arbitrary sharing profile attributes. Each attribute is simply a
-- name/value pair associated with a sharing profile. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE guacamole_sharing_profile_attribute (
`sharing_profile_id` int(11) NOT NULL,
`attribute_name` varchar(128) NOT NULL,
`attribute_value` varchar(4096) NOT NULL,
PRIMARY KEY (sharing_profile_id, attribute_name),
KEY `sharing_profile_id` (`sharing_profile_id`),
CONSTRAINT guacamole_sharing_profile_attribute_ibfk_1
FOREIGN KEY (sharing_profile_id)
REFERENCES guacamole_sharing_profile (sharing_profile_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of connection permissions. Each connection permission grants a user
-- specific access to a connection.

View File

@@ -0,0 +1,106 @@
--
-- 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.
--
--
-- Table of arbitrary user attributes. Each attribute is simply a name/value
-- pair associated with a user. Arbitrary attributes are defined by other
-- extensions. Attributes defined by this extension will be mapped to
-- properly-typed columns of a specific table.
--
CREATE TABLE guacamole_user_attribute (
`user_id` int(11) NOT NULL,
`attribute_name` varchar(128) NOT NULL,
`attribute_value` varchar(4096) NOT NULL,
PRIMARY KEY (user_id, attribute_name),
KEY `user_id` (`user_id`),
CONSTRAINT guacamole_user_attribute_ibfk_1
FOREIGN KEY (user_id)
REFERENCES guacamole_user (user_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of arbitrary connection attributes. Each attribute is simply a
-- name/value pair associated with a connection. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE guacamole_connection_attribute (
`connection_id` int(11) NOT NULL,
`attribute_name` varchar(128) NOT NULL,
`attribute_value` varchar(4096) NOT NULL,
PRIMARY KEY (connection_id, attribute_name),
KEY `connection_id` (`connection_id`),
CONSTRAINT guacamole_connection_attribute_ibfk_1
FOREIGN KEY (connection_id)
REFERENCES guacamole_connection (connection_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of arbitrary connection group attributes. Each attribute is simply a
-- name/value pair associated with a connection group. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE guacamole_connection_group_attribute (
`connection_group_id` int(11) NOT NULL,
`attribute_name` varchar(128) NOT NULL,
`attribute_value` varchar(4096) NOT NULL,
PRIMARY KEY (connection_group_id, attribute_name),
KEY `connection_group_id` (`connection_group_id`),
CONSTRAINT guacamole_connection_group_attribute_ibfk_1
FOREIGN KEY (connection_group_id)
REFERENCES guacamole_connection_group (connection_group_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table of arbitrary sharing profile attributes. Each attribute is simply a
-- name/value pair associated with a sharing profile. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE guacamole_sharing_profile_attribute (
`sharing_profile_id` int(11) NOT NULL,
`attribute_name` varchar(128) NOT NULL,
`attribute_value` varchar(4096) NOT NULL,
PRIMARY KEY (sharing_profile_id, attribute_name),
KEY `sharing_profile_id` (`sharing_profile_id`),
CONSTRAINT guacamole_sharing_profile_attribute_ibfk_1
FOREIGN KEY (sharing_profile_id)
REFERENCES guacamole_sharing_profile (sharing_profile_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

View File

@@ -47,6 +47,14 @@
<result column="sharing_profile_id"/>
</collection>
<!-- Arbitrary attributes -->
<collection property="arbitraryAttributes" resultSet="arbitraryAttributes"
ofType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel"
column="connection_id" foreignColumn="connection_id">
<result property="name" column="attribute_name" jdbcType="VARCHAR"/>
<result property="value" column="attribute_value" jdbcType="VARCHAR"/>
</collection>
</resultMap>
<!-- Select all connection identifiers -->
@@ -87,7 +95,7 @@
<!-- Select multiple connections by identifier -->
<select id="select" resultMap="ConnectionResultMap"
resultSets="connections,sharingProfiles">
resultSets="connections,sharingProfiles,arbitraryAttributes">
SELECT
guacamole_connection.connection_id,
@@ -119,11 +127,22 @@
#{identifier,jdbcType=VARCHAR}
</foreach>;
SELECT
connection_id,
attribute_name,
attribute_value
FROM guacamole_connection_attribute
WHERE connection_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>;
</select>
<!-- Select multiple connections by identifier only if readable -->
<select id="selectReadable" resultMap="ConnectionResultMap"
resultSets="connections,sharingProfiles">
resultSets="connections,sharingProfiles,arbitraryAttributes">
SELECT
guacamole_connection.connection_id,
@@ -161,6 +180,20 @@
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
SELECT
guacamole_connection_attribute.connection_id,
attribute_name,
attribute_value
FROM guacamole_connection_attribute
JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection_attribute.connection_id
WHERE guacamole_connection_attribute.connection_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
</select>
<!-- Select single connection by name -->
@@ -242,4 +275,25 @@
WHERE connection_id = #{object.objectID,jdbcType=INTEGER}
</update>
<!-- Delete attributes associated with connection -->
<delete id="deleteAttributes">
DELETE FROM guacamole_connection_attribute
WHERE connection_id = #{object.objectID,jdbcType=INTEGER}
</delete>
<!-- Insert attributes for connection -->
<insert id="insertAttributes" parameterType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel">
INSERT INTO guacamole_connection_attribute (
connection_id,
attribute_name,
attribute_value
)
VALUES
<foreach collection="object.arbitraryAttributes" item="attribute" separator=",">
(#{object.objectID,jdbcType=INTEGER},
#{attribute.name,jdbcType=VARCHAR},
#{attribute.value,jdbcType=VARCHAR})
</foreach>
</insert>
</mapper>

View File

@@ -48,6 +48,14 @@
<result column="connection_id"/>
</collection>
<!-- Arbitrary attributes -->
<collection property="arbitraryAttributes" resultSet="arbitraryAttributes"
ofType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel"
column="connection_group_id" foreignColumn="connection_group_id">
<result property="name" column="attribute_name" jdbcType="VARCHAR"/>
<result property="value" column="attribute_value" jdbcType="VARCHAR"/>
</collection>
</resultMap>
<!-- Select all connection group identifiers -->
@@ -88,7 +96,7 @@
<!-- Select multiple connection groups by identifier -->
<select id="select" resultMap="ConnectionGroupResultMap"
resultSets="connectionGroups,childConnectionGroups,childConnections">
resultSets="connectionGroups,childConnectionGroups,childConnections,arbitraryAttributes">
SELECT
connection_group_id,
@@ -121,11 +129,22 @@
#{identifier,jdbcType=VARCHAR}
</foreach>;
SELECT
connection_group_id,
attribute_name,
attribute_value
FROM guacamole_connection_group_attribute
WHERE connection_group_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>;
</select>
<!-- Select multiple connection groups by identifier only if readable -->
<select id="selectReadable" resultMap="ConnectionGroupResultMap"
resultSets="connectionGroups,childConnectionGroups,childConnections">
resultSets="connectionGroups,childConnectionGroups,childConnections,arbitraryAttributes">
SELECT
guacamole_connection_group.connection_group_id,
@@ -167,6 +186,20 @@
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
SELECT
guacamole_connection_group_attribute.connection_group_id,
attribute_name,
attribute_value
FROM guacamole_connection_group_attribute
JOIN guacamole_connection_group_permission ON guacamole_connection_group_permission.connection_group_id = guacamole_connection_group_attribute.connection_group_id
WHERE guacamole_connection_group_attribute.connection_group_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
</select>
<!-- Select single connection group by name -->
@@ -229,4 +262,25 @@
WHERE connection_group_id = #{object.objectID,jdbcType=INTEGER}
</update>
<!-- Delete attributes associated with connection group -->
<delete id="deleteAttributes">
DELETE FROM guacamole_connection_group_attribute
WHERE connection_group_id = #{object.objectID,jdbcType=INTEGER}
</delete>
<!-- Insert attributes for connection group -->
<insert id="insertAttributes" parameterType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel">
INSERT INTO guacamole_connection_group_attribute (
connection_group_id,
attribute_name,
attribute_value
)
VALUES
<foreach collection="object.arbitraryAttributes" item="attribute" separator=",">
(#{object.objectID,jdbcType=INTEGER},
#{attribute.name,jdbcType=VARCHAR},
#{attribute.value,jdbcType=VARCHAR})
</foreach>
</insert>
</mapper>

View File

@@ -25,9 +25,20 @@
<!-- Result mapper for sharing profile objects -->
<resultMap id="SharingProfileResultMap" type="org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileModel">
<!-- Sharing profile properties -->
<id column="sharing_profile_id" property="objectID" jdbcType="INTEGER"/>
<result column="sharing_profile_name" property="name" jdbcType="VARCHAR"/>
<result column="primary_connection_id" property="parentIdentifier" jdbcType="INTEGER"/>
<!-- Arbitrary attributes -->
<collection property="arbitraryAttributes" resultSet="arbitraryAttributes"
ofType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel"
column="sharing_profile_id" foreignColumn="sharing_profile_id">
<result property="name" column="attribute_name" jdbcType="VARCHAR"/>
<result property="value" column="attribute_value" jdbcType="VARCHAR"/>
</collection>
</resultMap>
<!-- Select all sharing profile identifiers -->
@@ -46,7 +57,8 @@
</select>
<!-- Select multiple sharing profiles by identifier -->
<select id="select" resultMap="SharingProfileResultMap">
<select id="select" resultMap="SharingProfileResultMap"
resultSets="sharingProfiles,arbitraryAttributes">
SELECT
sharing_profile_id,
@@ -57,12 +69,24 @@
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
</foreach>;
SELECT
sharing_profile_id,
attribute_name,
attribute_value
FROM guacamole_sharing_profile_attribute
WHERE sharing_profile_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>;
</select>
<!-- Select multiple sharing profiles by identifier only if readable -->
<select id="selectReadable" resultMap="SharingProfileResultMap">
<select id="selectReadable" resultMap="SharingProfileResultMap"
resultSets="sharingProfiles,arbitraryAttributes">
SELECT
guacamole_sharing_profile.sharing_profile_id,
@@ -76,7 +100,21 @@
#{identifier,jdbcType=VARCHAR}
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ'
AND permission = 'READ';
SELECT
guacamole_sharing_profile_attribute.sharing_profile_id,
attribute_name,
attribute_value
FROM guacamole_sharing_profile_attribute
JOIN guacamole_sharing_profile_permission ON guacamole_sharing_profile_permission.sharing_profile_id = guacamole_sharing_profile_attribute.sharing_profile_id
WHERE guacamole_sharing_profile_attribute.sharing_profile_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
</select>
@@ -123,4 +161,25 @@
WHERE sharing_profile_id = #{object.objectID,jdbcType=INTEGER}
</update>
<!-- Delete attributes associated with sharing profile -->
<delete id="deleteAttributes">
DELETE FROM guacamole_sharing_profile_attribute
WHERE sharing_profile_id = #{object.objectID,jdbcType=INTEGER}
</delete>
<!-- Insert attributes for sharing profile -->
<insert id="insertAttributes" parameterType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel">
INSERT INTO guacamole_sharing_profile_attribute (
sharing_profile_id,
attribute_name,
attribute_value
)
VALUES
<foreach collection="object.arbitraryAttributes" item="attribute" separator=",">
(#{object.objectID,jdbcType=INTEGER},
#{attribute.name,jdbcType=VARCHAR},
#{attribute.value,jdbcType=VARCHAR})
</foreach>
</insert>
</mapper>

View File

@@ -25,6 +25,8 @@
<!-- Result mapper for user objects -->
<resultMap id="UserResultMap" type="org.apache.guacamole.auth.jdbc.user.UserModel" >
<!-- User properties -->
<id column="user_id" property="objectID" jdbcType="INTEGER"/>
<result column="username" property="identifier" jdbcType="VARCHAR"/>
<result column="password_hash" property="passwordHash" jdbcType="BINARY"/>
@@ -42,6 +44,15 @@
<result column="organization" property="organization" jdbcType="VARCHAR"/>
<result column="organizational_role" property="organizationalRole" jdbcType="VARCHAR"/>
<result column="last_active" property="lastActive" jdbcType="TIMESTAMP"/>
<!-- Arbitrary attributes -->
<collection property="arbitraryAttributes" resultSet="arbitraryAttributes"
ofType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel"
column="user_id" foreignColumn="user_id">
<result property="name" column="attribute_name" jdbcType="VARCHAR"/>
<result property="value" column="attribute_value" jdbcType="VARCHAR"/>
</collection>
</resultMap>
<!-- Select all usernames -->
@@ -61,7 +72,8 @@
</select>
<!-- Select multiple users by username -->
<select id="select" resultMap="UserResultMap">
<select id="select" resultMap="UserResultMap"
resultSets="users,arbitraryAttributes">
SELECT
guacamole_user.user_id,
@@ -88,12 +100,25 @@
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
GROUP BY guacamole_user.user_id
GROUP BY guacamole_user.user_id;
SELECT
guacamole_user_attribute.user_id,
guacamole_user_attribute.attribute_name,
guacamole_user_attribute.attribute_value
FROM guacamole_user_attribute
JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
WHERE username IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>;
</select>
<!-- Select multiple users by username only if readable -->
<select id="selectReadable" resultMap="UserResultMap">
<select id="selectReadable" resultMap="UserResultMap"
resultSets="users,arbitraryAttributes">
SELECT
guacamole_user.user_id,
@@ -123,12 +148,28 @@
</foreach>
AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ'
GROUP BY guacamole_user.user_id
GROUP BY guacamole_user.user_id;
SELECT
guacamole_user_attribute.user_id,
guacamole_user_attribute.attribute_name,
guacamole_user_attribute.attribute_value
FROM guacamole_user_attribute
JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
WHERE username IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
</select>
<!-- Select single user by username -->
<select id="selectOne" resultMap="UserResultMap">
<select id="selectOne" resultMap="UserResultMap"
resultSets="users,arbitraryAttributes">
SELECT
guacamole_user.user_id,
@@ -152,7 +193,15 @@
LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
WHERE
guacamole_user.username = #{username,jdbcType=VARCHAR}
GROUP BY guacamole_user.user_id
GROUP BY guacamole_user.user_id;
SELECT
guacamole_user_attribute.user_id,
guacamole_user_attribute.attribute_name,
guacamole_user_attribute.attribute_value
FROM guacamole_user_attribute
JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
WHERE username = #{username,jdbcType=VARCHAR};
</select>
@@ -223,4 +272,25 @@
WHERE user_id = #{object.objectID,jdbcType=VARCHAR}
</update>
</mapper>
<!-- Delete attributes associated with user -->
<delete id="deleteAttributes">
DELETE FROM guacamole_user_attribute
WHERE user_id = #{object.objectID,jdbcType=INTEGER}
</delete>
<!-- Insert attributes for user -->
<insert id="insertAttributes" parameterType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel">
INSERT INTO guacamole_user_attribute (
user_id,
attribute_name,
attribute_value
)
VALUES
<foreach collection="object.arbitraryAttributes" item="attribute" separator=",">
(#{object.objectID,jdbcType=INTEGER},
#{attribute.name,jdbcType=VARCHAR},
#{attribute.value,jdbcType=VARCHAR})
</foreach>
</insert>
</mapper>

View File

@@ -251,6 +251,102 @@ CREATE TABLE guacamole_sharing_profile_parameter (
CREATE INDEX guacamole_sharing_profile_parameter_sharing_profile_id
ON guacamole_sharing_profile_parameter(sharing_profile_id);
--
-- Table of arbitrary user attributes. Each attribute is simply a name/value
-- pair associated with a user. Arbitrary attributes are defined by other
-- extensions. Attributes defined by this extension will be mapped to
-- properly-typed columns of a specific table.
--
CREATE TABLE guacamole_user_attribute (
user_id integer NOT NULL,
attribute_name varchar(128) NOT NULL,
attribute_value varchar(4096) NOT NULL,
PRIMARY KEY (user_id, attribute_name),
CONSTRAINT guacamole_user_attribute_ibfk_1
FOREIGN KEY (user_id)
REFERENCES guacamole_user (user_id) ON DELETE CASCADE
);
CREATE INDEX guacamole_user_attribute_user_id
ON guacamole_user_attribute(user_id);
--
-- Table of arbitrary connection attributes. Each attribute is simply a
-- name/value pair associated with a connection. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE guacamole_connection_attribute (
connection_id integer NOT NULL,
attribute_name varchar(128) NOT NULL,
attribute_value varchar(4096) NOT NULL,
PRIMARY KEY (connection_id, attribute_name),
CONSTRAINT guacamole_connection_attribute_ibfk_1
FOREIGN KEY (connection_id)
REFERENCES guacamole_connection (connection_id) ON DELETE CASCADE
);
CREATE INDEX guacamole_connection_attribute_connection_id
ON guacamole_connection_attribute(connection_id);
--
-- Table of arbitrary connection group attributes. Each attribute is simply a
-- name/value pair associated with a connection group. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE guacamole_connection_group_attribute (
connection_group_id integer NOT NULL,
attribute_name varchar(128) NOT NULL,
attribute_value varchar(4096) NOT NULL,
PRIMARY KEY (connection_group_id, attribute_name),
CONSTRAINT guacamole_connection_group_attribute_ibfk_1
FOREIGN KEY (connection_group_id)
REFERENCES guacamole_connection_group (connection_group_id) ON DELETE CASCADE
);
CREATE INDEX guacamole_connection_group_attribute_connection_group_id
ON guacamole_connection_group_attribute(connection_group_id);
--
-- Table of arbitrary sharing profile attributes. Each attribute is simply a
-- name/value pair associated with a sharing profile. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE guacamole_sharing_profile_attribute (
sharing_profile_id integer NOT NULL,
attribute_name varchar(128) NOT NULL,
attribute_value varchar(4096) NOT NULL,
PRIMARY KEY (sharing_profile_id, attribute_name),
CONSTRAINT guacamole_sharing_profile_attribute_ibfk_1
FOREIGN KEY (sharing_profile_id)
REFERENCES guacamole_sharing_profile (sharing_profile_id) ON DELETE CASCADE
);
CREATE INDEX guacamole_sharing_profile_attribute_sharing_profile_id
ON guacamole_sharing_profile_attribute(sharing_profile_id);
--
-- Table of connection permissions. Each connection permission grants a user
-- specific access to a connection.

View File

@@ -0,0 +1,114 @@
--
-- 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.
--
--
-- Table of arbitrary user attributes. Each attribute is simply a name/value
-- pair associated with a user. Arbitrary attributes are defined by other
-- extensions. Attributes defined by this extension will be mapped to
-- properly-typed columns of a specific table.
--
CREATE TABLE guacamole_user_attribute (
user_id integer NOT NULL,
attribute_name varchar(128) NOT NULL,
attribute_value varchar(4096) NOT NULL,
PRIMARY KEY (user_id, attribute_name),
CONSTRAINT guacamole_user_attribute_ibfk_1
FOREIGN KEY (user_id)
REFERENCES guacamole_user (user_id) ON DELETE CASCADE
);
CREATE INDEX guacamole_user_attribute_user_id
ON guacamole_user_attribute(user_id);
--
-- Table of arbitrary connection attributes. Each attribute is simply a
-- name/value pair associated with a connection. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE guacamole_connection_attribute (
connection_id integer NOT NULL,
attribute_name varchar(128) NOT NULL,
attribute_value varchar(4096) NOT NULL,
PRIMARY KEY (connection_id, attribute_name),
CONSTRAINT guacamole_connection_attribute_ibfk_1
FOREIGN KEY (connection_id)
REFERENCES guacamole_connection (connection_id) ON DELETE CASCADE
);
CREATE INDEX guacamole_connection_attribute_connection_id
ON guacamole_connection_attribute(connection_id);
--
-- Table of arbitrary connection group attributes. Each attribute is simply a
-- name/value pair associated with a connection group. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE guacamole_connection_group_attribute (
connection_group_id integer NOT NULL,
attribute_name varchar(128) NOT NULL,
attribute_value varchar(4096) NOT NULL,
PRIMARY KEY (connection_group_id, attribute_name),
CONSTRAINT guacamole_connection_group_attribute_ibfk_1
FOREIGN KEY (connection_group_id)
REFERENCES guacamole_connection_group (connection_group_id) ON DELETE CASCADE
);
CREATE INDEX guacamole_connection_group_attribute_connection_group_id
ON guacamole_connection_group_attribute(connection_group_id);
--
-- Table of arbitrary sharing profile attributes. Each attribute is simply a
-- name/value pair associated with a sharing profile. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE guacamole_sharing_profile_attribute (
sharing_profile_id integer NOT NULL,
attribute_name varchar(128) NOT NULL,
attribute_value varchar(4096) NOT NULL,
PRIMARY KEY (sharing_profile_id, attribute_name),
CONSTRAINT guacamole_sharing_profile_attribute_ibfk_1
FOREIGN KEY (sharing_profile_id)
REFERENCES guacamole_sharing_profile (sharing_profile_id) ON DELETE CASCADE
);
CREATE INDEX guacamole_sharing_profile_attribute_sharing_profile_id
ON guacamole_sharing_profile_attribute(sharing_profile_id);

View File

@@ -47,6 +47,14 @@
<result column="sharing_profile_id"/>
</collection>
<!-- Arbitrary attributes -->
<collection property="arbitraryAttributes" resultSet="arbitraryAttributes"
ofType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel"
column="connection_id" foreignColumn="connection_id">
<result property="name" column="attribute_name" jdbcType="VARCHAR"/>
<result property="value" column="attribute_value" jdbcType="VARCHAR"/>
</collection>
</resultMap>
<!-- Select all connection identifiers -->
@@ -87,7 +95,7 @@
<!-- Select multiple connections by identifier -->
<select id="select" resultMap="ConnectionResultMap"
resultSets="connections,sharingProfiles">
resultSets="connections,sharingProfiles,arbitraryAttributes">
SELECT
guacamole_connection.connection_id,
@@ -119,11 +127,22 @@
#{identifier,jdbcType=INTEGER}::integer
</foreach>;
SELECT
connection_id,
attribute_name,
attribute_value
FROM guacamole_connection_attribute
WHERE connection_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer
</foreach>;
</select>
<!-- Select multiple connections by identifier only if readable -->
<select id="selectReadable" resultMap="ConnectionResultMap"
resultSets="connections,sharingProfiles">
resultSets="connections,sharingProfiles,arbitraryAttributes">
SELECT
guacamole_connection.connection_id,
@@ -161,6 +180,20 @@
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
SELECT
guacamole_connection_attribute.connection_id,
attribute_name,
attribute_value
FROM guacamole_connection_attribute
JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection_attribute.connection_id
WHERE guacamole_connection_attribute.connection_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
</select>
<!-- Select single connection by name -->
@@ -242,4 +275,25 @@
WHERE connection_id = #{object.objectID,jdbcType=INTEGER}::integer
</update>
<!-- Delete attributes associated with connection -->
<delete id="deleteAttributes">
DELETE FROM guacamole_connection_attribute
WHERE connection_id = #{object.objectID,jdbcType=INTEGER}
</delete>
<!-- Insert attributes for connection -->
<insert id="insertAttributes" parameterType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel">
INSERT INTO guacamole_connection_attribute (
connection_id,
attribute_name,
attribute_value
)
VALUES
<foreach collection="object.arbitraryAttributes" item="attribute" separator=",">
(#{object.objectID,jdbcType=INTEGER},
#{attribute.name,jdbcType=VARCHAR},
#{attribute.value,jdbcType=VARCHAR})
</foreach>
</insert>
</mapper>

View File

@@ -48,6 +48,14 @@
<result column="connection_id"/>
</collection>
<!-- Arbitrary attributes -->
<collection property="arbitraryAttributes" resultSet="arbitraryAttributes"
ofType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel"
column="connection_group_id" foreignColumn="connection_group_id">
<result property="name" column="attribute_name" jdbcType="VARCHAR"/>
<result property="value" column="attribute_value" jdbcType="VARCHAR"/>
</collection>
</resultMap>
<!-- Select all connection group identifiers -->
@@ -88,7 +96,7 @@
<!-- Select multiple connection groups by identifier -->
<select id="select" resultMap="ConnectionGroupResultMap"
resultSets="connectionGroups,childConnectionGroups,childConnections">
resultSets="connectionGroups,childConnectionGroups,childConnections,arbitraryAttributes">
SELECT
connection_group_id,
@@ -121,11 +129,22 @@
#{identifier,jdbcType=INTEGER}::integer
</foreach>;
SELECT
connection_group_id,
attribute_name,
attribute_value
FROM guacamole_connection_group_attribute
WHERE connection_group_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer
</foreach>;
</select>
<!-- Select multiple connection groups by identifier only if readable -->
<select id="selectReadable" resultMap="ConnectionGroupResultMap"
resultSets="connectionGroups,childConnectionGroups,childConnections">
resultSets="connectionGroups,childConnectionGroups,childConnections,arbitraryAttributes">
SELECT
guacamole_connection_group.connection_group_id,
@@ -167,6 +186,20 @@
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
SELECT
guacamole_connection_group_attribute.connection_group_id,
attribute_name,
attribute_value
FROM guacamole_connection_group_attribute
JOIN guacamole_connection_group_permission ON guacamole_connection_group_permission.connection_group_id = guacamole_connection_group_attribute.connection_group_id
WHERE guacamole_connection_group_attribute.connection_group_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
</select>
<!-- Select single connection group by name -->
@@ -229,4 +262,25 @@
WHERE connection_group_id = #{object.objectID,jdbcType=INTEGER}::integer
</update>
<!-- Delete attributes associated with connection group -->
<delete id="deleteAttributes">
DELETE FROM guacamole_connection_group_attribute
WHERE connection_group_id = #{object.objectID,jdbcType=INTEGER}
</delete>
<!-- Insert attributes for connection group -->
<insert id="insertAttributes" parameterType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel">
INSERT INTO guacamole_connection_group_attribute (
connection_group_id,
attribute_name,
attribute_value
)
VALUES
<foreach collection="object.arbitraryAttributes" item="attribute" separator=",">
(#{object.objectID,jdbcType=INTEGER},
#{attribute.name,jdbcType=VARCHAR},
#{attribute.value,jdbcType=VARCHAR})
</foreach>
</insert>
</mapper>

View File

@@ -25,9 +25,20 @@
<!-- Result mapper for sharing profile objects -->
<resultMap id="SharingProfileResultMap" type="org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileModel">
<!-- Sharing profile properties -->
<id column="sharing_profile_id" property="objectID" jdbcType="INTEGER"/>
<result column="sharing_profile_name" property="name" jdbcType="VARCHAR"/>
<result column="primary_connection_id" property="parentIdentifier" jdbcType="INTEGER"/>
<!-- Arbitrary attributes -->
<collection property="arbitraryAttributes" resultSet="arbitraryAttributes"
ofType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel"
column="sharing_profile_id" foreignColumn="sharing_profile_id">
<result property="name" column="attribute_name" jdbcType="VARCHAR"/>
<result property="value" column="attribute_value" jdbcType="VARCHAR"/>
</collection>
</resultMap>
<!-- Select all sharing profile identifiers -->
@@ -46,7 +57,8 @@
</select>
<!-- Select multiple sharing profiles by identifier -->
<select id="select" resultMap="SharingProfileResultMap">
<select id="select" resultMap="SharingProfileResultMap"
resultSets="sharingProfiles,arbitraryAttributes">
SELECT
sharing_profile_id,
@@ -57,12 +69,24 @@
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer
</foreach>
</foreach>;
SELECT
sharing_profile_id,
attribute_name,
attribute_value
FROM guacamole_sharing_profile_attribute
WHERE sharing_profile_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer
</foreach>;
</select>
<!-- Select multiple sharing profiles by identifier only if readable -->
<select id="selectReadable" resultMap="SharingProfileResultMap">
<select id="selectReadable" resultMap="SharingProfileResultMap"
resultSets="sharingProfiles,arbitraryAttributes">
SELECT
guacamole_sharing_profile.sharing_profile_id,
@@ -76,7 +100,21 @@
#{identifier,jdbcType=INTEGER}::integer
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ'
AND permission = 'READ';
SELECT
guacamole_sharing_profile_attribute.sharing_profile_id,
attribute_name,
attribute_value
FROM guacamole_sharing_profile_attribute
JOIN guacamole_sharing_profile_permission ON guacamole_sharing_profile_permission.sharing_profile_id = guacamole_sharing_profile_attribute.sharing_profile_id
WHERE guacamole_sharing_profile_attribute.sharing_profile_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}::integer
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
</select>
@@ -123,4 +161,25 @@
WHERE sharing_profile_id = #{object.objectID,jdbcType=INTEGER}::integer
</update>
<!-- Delete attributes associated with sharing profile -->
<delete id="deleteAttributes">
DELETE FROM guacamole_sharing_profile_attribute
WHERE sharing_profile_id = #{object.objectID,jdbcType=INTEGER}
</delete>
<!-- Insert attributes for sharing profile -->
<insert id="insertAttributes" parameterType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel">
INSERT INTO guacamole_sharing_profile_attribute (
sharing_profile_id,
attribute_name,
attribute_value
)
VALUES
<foreach collection="object.arbitraryAttributes" item="attribute" separator=",">
(#{object.objectID,jdbcType=INTEGER},
#{attribute.name,jdbcType=VARCHAR},
#{attribute.value,jdbcType=VARCHAR})
</foreach>
</insert>
</mapper>

View File

@@ -25,6 +25,8 @@
<!-- Result mapper for user objects -->
<resultMap id="UserResultMap" type="org.apache.guacamole.auth.jdbc.user.UserModel" >
<!-- User properties -->
<id column="user_id" property="objectID" jdbcType="INTEGER"/>
<result column="username" property="identifier" jdbcType="VARCHAR"/>
<result column="password_hash" property="passwordHash" jdbcType="BINARY"/>
@@ -42,6 +44,15 @@
<result column="organization" property="organization" jdbcType="VARCHAR"/>
<result column="organizational_role" property="organizationalRole" jdbcType="VARCHAR"/>
<result column="last_active" property="lastActive" jdbcType="TIMESTAMP"/>
<!-- Arbitrary attributes -->
<collection property="arbitraryAttributes" resultSet="arbitraryAttributes"
ofType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel"
column="user_id" foreignColumn="user_id">
<result property="name" column="attribute_name" jdbcType="VARCHAR"/>
<result property="value" column="attribute_value" jdbcType="VARCHAR"/>
</collection>
</resultMap>
<!-- Select all usernames -->
@@ -61,7 +72,8 @@
</select>
<!-- Select multiple users by username -->
<select id="select" resultMap="UserResultMap">
<select id="select" resultMap="UserResultMap"
resultSets="users,arbitraryAttributes">
SELECT
guacamole_user.user_id,
@@ -88,12 +100,25 @@
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
GROUP BY guacamole_user.user_id
GROUP BY guacamole_user.user_id;
SELECT
guacamole_user_attribute.user_id,
guacamole_user_attribute.attribute_name,
guacamole_user_attribute.attribute_value
FROM guacamole_user_attribute
JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
WHERE username IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>;
</select>
<!-- Select multiple users by username only if readable -->
<select id="selectReadable" resultMap="UserResultMap">
<select id="selectReadable" resultMap="UserResultMap"
resultSets="users,arbitraryAttributes">
SELECT
guacamole_user.user_id,
@@ -123,12 +148,28 @@
</foreach>
AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ'
GROUP BY guacamole_user.user_id
GROUP BY guacamole_user.user_id;
SELECT
guacamole_user_attribute.user_id,
guacamole_user_attribute.attribute_name,
guacamole_user_attribute.attribute_value
FROM guacamole_user_attribute
JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id
WHERE username IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=VARCHAR}
</foreach>
AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
</select>
<!-- Select single user by username -->
<select id="selectOne" resultMap="UserResultMap">
<select id="selectOne" resultMap="UserResultMap"
resultSets="users,arbitraryAttributes">
SELECT
guacamole_user.user_id,
@@ -152,7 +193,15 @@
LEFT JOIN guacamole_user_history ON guacamole_user_history.user_id = guacamole_user.user_id
WHERE
guacamole_user.username = #{username,jdbcType=VARCHAR}
GROUP BY guacamole_user.user_id
GROUP BY guacamole_user.user_id;
SELECT
guacamole_user_attribute.user_id,
guacamole_user_attribute.attribute_name,
guacamole_user_attribute.attribute_value
FROM guacamole_user_attribute
JOIN guacamole_user ON guacamole_user.user_id = guacamole_user_attribute.user_id
WHERE username = #{username,jdbcType=VARCHAR};
</select>
@@ -223,4 +272,25 @@
WHERE user_id = #{object.objectID,jdbcType=VARCHAR}
</update>
<!-- Delete attributes associated with user -->
<delete id="deleteAttributes">
DELETE FROM guacamole_user_attribute
WHERE user_id = #{object.objectID,jdbcType=INTEGER}
</delete>
<!-- Insert attributes for user -->
<insert id="insertAttributes" parameterType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel">
INSERT INTO guacamole_user_attribute (
user_id,
attribute_name,
attribute_value
)
VALUES
<foreach collection="object.arbitraryAttributes" item="attribute" separator=",">
(#{object.objectID,jdbcType=INTEGER},
#{attribute.name,jdbcType=VARCHAR},
#{attribute.value,jdbcType=VARCHAR})
</foreach>
</insert>
</mapper>

View File

@@ -241,6 +241,115 @@ CREATE NONCLUSTERED INDEX [IX_guacamole_sharing_profile_primary_connection_id]
ON [guacamole_sharing_profile] ([primary_connection_id]);
GO
--
-- Table of arbitrary user attributes. Each attribute is simply a name/value
-- pair associated with a user. Arbitrary attributes are defined by other
-- extensions. Attributes defined by this extension will be mapped to
-- properly-typed columns of a specific table.
--
CREATE TABLE [guacamole_user_attribute] (
[user_id] [int] NOT NULL,
[attribute_name] [nvarchar](128) NOT NULL,
[attribute_value] [nvarchar](4000) NOT NULL,
CONSTRAINT [PK_guacamole_user_attribute]
PRIMARY KEY CLUSTERED ([user_id], [attribute_name]),
CONSTRAINT [FK_guacamole_user_attribute_user_id]
FOREIGN KEY ([user_id])
REFERENCES [guacamole_user] ([user_id])
ON DELETE CASCADE
);
CREATE NONCLUSTERED INDEX [IX_guacamole_user_attribute_user_id]
ON [guacamole_user_attribute] ([user_id])
INCLUDE ([attribute_name], [attribute_value]);
GO
--
-- Table of arbitrary connection attributes. Each attribute is simply a
-- name/value pair associated with a connection. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE [guacamole_connection_attribute] (
[connection_id] [int] NOT NULL,
[attribute_name] [nvarchar](128) NOT NULL,
[attribute_value] [nvarchar](4000) NOT NULL,
PRIMARY KEY (connection_id, attribute_name),
CONSTRAINT [FK_guacamole_connection_attribute_connection_id]
FOREIGN KEY ([connection_id])
REFERENCES [guacamole_connection] ([connection_id])
ON DELETE CASCADE
);
CREATE NONCLUSTERED INDEX [IX_guacamole_connection_attribute_connection_id]
ON [guacamole_connection_attribute] ([connection_id])
INCLUDE ([attribute_name], [attribute_value]);
GO
--
-- Table of arbitrary connection group attributes. Each attribute is simply a
-- name/value pair associated with a connection group. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE [guacamole_connection_group_attribute] (
[connection_group_id] [int] NOT NULL,
[attribute_name] [nvarchar](128) NOT NULL,
[attribute_value] [nvarchar](4000) NOT NULL,
PRIMARY KEY (connection_group_id, attribute_name),
CONSTRAINT [FK_guacamole_connection_group_attribute_connection_group_id]
FOREIGN KEY ([connection_group_id])
REFERENCES [guacamole_connection_group] ([connection_group_id])
ON DELETE CASCADE
);
CREATE NONCLUSTERED INDEX [IX_guacamole_connection_group_attribute_connection_group_id]
ON [guacamole_connection_group_attribute] ([connection_group_id])
INCLUDE ([attribute_name], [attribute_value]);
GO
--
-- Table of arbitrary sharing profile attributes. Each attribute is simply a
-- name/value pair associated with a sharing profile. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE [guacamole_sharing_profile_attribute] (
[sharing_profile_id] [int] NOT NULL,
[attribute_name] [nvarchar](128) NOT NULL,
[attribute_value] [nvarchar](4000) NOT NULL,
PRIMARY KEY (sharing_profile_id, attribute_name),
CONSTRAINT [FK_guacamole_sharing_profile_attribute_sharing_profile_id]
FOREIGN KEY ([sharing_profile_id])
REFERENCES [guacamole_sharing_profile] ([sharing_profile_id])
ON DELETE CASCADE
);
CREATE NONCLUSTERED INDEX [IX_guacamole_sharing_profile_attribute_sharing_profile_id]
ON [guacamole_sharing_profile_attribute] ([sharing_profile_id])
INCLUDE ([attribute_name], [attribute_value]);
GO
--
-- Table of connection parameters. Each parameter is simply a name/value pair
-- associated with a connection.
@@ -683,3 +792,4 @@ AS BEGIN
END
GO

View File

@@ -0,0 +1,127 @@
--
-- 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.
--
--
-- Table of arbitrary user attributes. Each attribute is simply a name/value
-- pair associated with a user. Arbitrary attributes are defined by other
-- extensions. Attributes defined by this extension will be mapped to
-- properly-typed columns of a specific table.
--
CREATE TABLE [guacamole_user_attribute] (
[user_id] [int] NOT NULL,
[attribute_name] [nvarchar](128) NOT NULL,
[attribute_value] [nvarchar](4000) NOT NULL,
CONSTRAINT [PK_guacamole_user_attribute]
PRIMARY KEY CLUSTERED ([user_id], [attribute_name]),
CONSTRAINT [FK_guacamole_user_attribute_user_id]
FOREIGN KEY ([user_id])
REFERENCES [guacamole_user] ([user_id])
ON DELETE CASCADE
);
CREATE NONCLUSTERED INDEX [IX_guacamole_user_attribute_user_id]
ON [guacamole_user_attribute] ([user_id])
INCLUDE ([attribute_name], [attribute_value]);
GO
--
-- Table of arbitrary connection attributes. Each attribute is simply a
-- name/value pair associated with a connection. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE [guacamole_connection_attribute] (
[connection_id] [int] NOT NULL,
[attribute_name] [nvarchar](128) NOT NULL,
[attribute_value] [nvarchar](4000) NOT NULL,
PRIMARY KEY (connection_id, attribute_name),
CONSTRAINT [FK_guacamole_connection_attribute_connection_id]
FOREIGN KEY ([connection_id])
REFERENCES [guacamole_connection] ([connection_id])
ON DELETE CASCADE
);
CREATE NONCLUSTERED INDEX [IX_guacamole_connection_attribute_connection_id]
ON [guacamole_connection_attribute] ([connection_id])
INCLUDE ([attribute_name], [attribute_value]);
GO
--
-- Table of arbitrary connection group attributes. Each attribute is simply a
-- name/value pair associated with a connection group. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE [guacamole_connection_group_attribute] (
[connection_group_id] [int] NOT NULL,
[attribute_name] [nvarchar](128) NOT NULL,
[attribute_value] [nvarchar](4000) NOT NULL,
PRIMARY KEY (connection_group_id, attribute_name),
CONSTRAINT [FK_guacamole_connection_group_attribute_connection_group_id]
FOREIGN KEY ([connection_group_id])
REFERENCES [guacamole_connection_group] ([connection_group_id])
ON DELETE CASCADE
);
CREATE NONCLUSTERED INDEX [IX_guacamole_connection_group_attribute_connection_group_id]
ON [guacamole_connection_group_attribute] ([connection_group_id])
INCLUDE ([attribute_name], [attribute_value]);
GO
--
-- Table of arbitrary sharing profile attributes. Each attribute is simply a
-- name/value pair associated with a sharing profile. Arbitrary attributes are
-- defined by other extensions. Attributes defined by this extension will be
-- mapped to properly-typed columns of a specific table.
--
CREATE TABLE [guacamole_sharing_profile_attribute] (
[sharing_profile_id] [int] NOT NULL,
[attribute_name] [nvarchar](128) NOT NULL,
[attribute_value] [nvarchar](4000) NOT NULL,
PRIMARY KEY (sharing_profile_id, attribute_name),
CONSTRAINT [FK_guacamole_sharing_profile_attribute_sharing_profile_id]
FOREIGN KEY ([sharing_profile_id])
REFERENCES [guacamole_sharing_profile] ([sharing_profile_id])
ON DELETE CASCADE
);
CREATE NONCLUSTERED INDEX [IX_guacamole_sharing_profile_attribute_sharing_profile_id]
ON [guacamole_sharing_profile_attribute] ([sharing_profile_id])
INCLUDE ([attribute_name], [attribute_value]);
GO

View File

@@ -47,6 +47,14 @@
<result column="sharing_profile_id"/>
</collection>
<!-- Arbitrary attributes -->
<collection property="arbitraryAttributes" resultSet="arbitraryAttributes"
ofType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel"
column="connection_id" foreignColumn="connection_id">
<result property="name" column="attribute_name" jdbcType="VARCHAR"/>
<result property="value" column="attribute_value" jdbcType="VARCHAR"/>
</collection>
</resultMap>
<!-- Select all connection identifiers -->
@@ -87,7 +95,7 @@
<!-- Select multiple connections by identifier -->
<select id="select" resultMap="ConnectionResultMap"
resultSets="connections,sharingProfiles">
resultSets="connections,sharingProfiles,arbitraryAttributes">
SELECT
[guacamole_connection].connection_id,
@@ -121,11 +129,22 @@
#{identifier,jdbcType=INTEGER}
</foreach>;
SELECT
connection_id,
attribute_name,
attribute_value
FROM [guacamole_connection_attribute]
WHERE connection_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}
</foreach>;
</select>
<!-- Select multiple connections by identifier only if readable -->
<select id="selectReadable" resultMap="ConnectionResultMap"
resultSets="connections,sharingProfiles">
resultSets="connections,sharingProfiles,arbitraryAttributes">
SELECT
[guacamole_connection].connection_id,
@@ -165,6 +184,20 @@
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
SELECT
[guacamole_connection_attribute].connection_id,
attribute_name,
attribute_value
FROM [guacamole_connection_attribute]
JOIN [guacamole_connection_permission] ON [guacamole_connection_permission].connection_id = [guacamole_connection_attribute].connection_id
WHERE [guacamole_connection_attribute].connection_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
</select>
<!-- Select single connection by name -->
@@ -248,4 +281,25 @@
WHERE connection_id = #{object.objectID,jdbcType=INTEGER}
</update>
<!-- Delete attributes associated with connection -->
<delete id="deleteAttributes">
DELETE FROM [guacamole_connection_attribute]
WHERE connection_id = #{object.objectID,jdbcType=INTEGER}
</delete>
<!-- Insert attributes for connection -->
<insert id="insertAttributes" parameterType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel">
INSERT INTO [guacamole_connection_attribute] (
connection_id,
attribute_name,
attribute_value
)
VALUES
<foreach collection="object.arbitraryAttributes" item="attribute" separator=",">
(#{object.objectID,jdbcType=INTEGER},
#{attribute.name,jdbcType=VARCHAR},
#{attribute.value,jdbcType=VARCHAR})
</foreach>
</insert>
</mapper>

View File

@@ -48,6 +48,14 @@
<result column="connection_id"/>
</collection>
<!-- Arbitrary attributes -->
<collection property="arbitraryAttributes" resultSet="arbitraryAttributes"
ofType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel"
column="connection_group_id" foreignColumn="connection_group_id">
<result property="name" column="attribute_name" jdbcType="VARCHAR"/>
<result property="value" column="attribute_value" jdbcType="VARCHAR"/>
</collection>
</resultMap>
<!-- Select all connection group identifiers -->
@@ -88,7 +96,7 @@
<!-- Select multiple connection groups by identifier -->
<select id="select" resultMap="ConnectionGroupResultMap"
resultSets="connectionGroups,childConnectionGroups,childConnections">
resultSets="connectionGroups,childConnectionGroups,childConnections,arbitraryAttributes">
SELECT
connection_group_id,
@@ -121,11 +129,22 @@
#{identifier,jdbcType=INTEGER}
</foreach>;
SELECT
connection_group_id,
attribute_name,
attribute_value
FROM [guacamole_connection_group_attribute]
WHERE connection_group_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}
</foreach>;
</select>
<!-- Select multiple connection groups by identifier only if readable -->
<select id="selectReadable" resultMap="ConnectionGroupResultMap"
resultSets="connectionGroups,childConnectionGroups,childConnections">
resultSets="connectionGroups,childConnectionGroups,childConnections,arbitraryAttributes">
SELECT
[guacamole_connection_group].connection_group_id,
@@ -167,6 +186,20 @@
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
SELECT
[guacamole_connection_group_attribute].connection_group_id,
attribute_name,
attribute_value
FROM [guacamole_connection_group_attribute]
JOIN [guacamole_connection_group_permission] ON [guacamole_connection_group_permission].connection_group_id = [guacamole_connection_group_attribute].connection_group_id
WHERE [guacamole_connection_group_attribute].connection_group_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
</select>
<!-- Select single connection group by name -->
@@ -229,4 +262,25 @@
WHERE connection_group_id = #{object.objectID,jdbcType=INTEGER}
</update>
<!-- Delete attributes associated with connection group -->
<delete id="deleteAttributes">
DELETE FROM [guacamole_connection_group_attribute]
WHERE connection_group_id = #{object.objectID,jdbcType=INTEGER}
</delete>
<!-- Insert attributes for connection group -->
<insert id="insertAttributes" parameterType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel">
INSERT INTO [guacamole_connection_group_attribute] (
connection_group_id,
attribute_name,
attribute_value
)
VALUES
<foreach collection="object.arbitraryAttributes" item="attribute" separator=",">
(#{object.objectID,jdbcType=INTEGER},
#{attribute.name,jdbcType=VARCHAR},
#{attribute.value,jdbcType=VARCHAR})
</foreach>
</insert>
</mapper>

View File

@@ -25,9 +25,20 @@
<!-- Result mapper for sharing profile objects -->
<resultMap id="SharingProfileResultMap" type="org.apache.guacamole.auth.jdbc.sharingprofile.SharingProfileModel">
<!-- Sharing profile properties -->
<id column="sharing_profile_id" property="objectID" jdbcType="INTEGER"/>
<result column="sharing_profile_name" property="name" jdbcType="VARCHAR"/>
<result column="primary_connection_id" property="parentIdentifier" jdbcType="INTEGER"/>
<!-- Arbitrary attributes -->
<collection property="arbitraryAttributes" resultSet="arbitraryAttributes"
ofType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel"
column="sharing_profile_id" foreignColumn="sharing_profile_id">
<result property="name" column="attribute_name" jdbcType="VARCHAR"/>
<result property="value" column="attribute_value" jdbcType="VARCHAR"/>
</collection>
</resultMap>
<!-- Select all sharing profile identifiers -->
@@ -46,7 +57,8 @@
</select>
<!-- Select multiple sharing profiles by identifier -->
<select id="select" resultMap="SharingProfileResultMap">
<select id="select" resultMap="SharingProfileResultMap"
resultSets="sharingProfiles,arbitraryAttributes">
SELECT
sharing_profile_id,
@@ -57,12 +69,24 @@
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}
</foreach>
</foreach>;
SELECT
sharing_profile_id,
attribute_name,
attribute_value
FROM [guacamole_sharing_profile_attribute]
WHERE sharing_profile_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}
</foreach>;
</select>
<!-- Select multiple sharing profiles by identifier only if readable -->
<select id="selectReadable" resultMap="SharingProfileResultMap">
<select id="selectReadable" resultMap="SharingProfileResultMap"
resultSets="sharingProfiles,arbitraryAttributes">
SELECT
[guacamole_sharing_profile].sharing_profile_id,
@@ -76,7 +100,21 @@
#{identifier,jdbcType=INTEGER}
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ'
AND permission = 'READ';
SELECT
[guacamole_sharing_profile_attribute].sharing_profile_id,
attribute_name,
attribute_value
FROM [guacamole_sharing_profile_attribute]
JOIN [guacamole_sharing_profile_permission] ON [guacamole_sharing_profile_permission].sharing_profile_id = [guacamole_sharing_profile_attribute].sharing_profile_id
WHERE [guacamole_sharing_profile_attribute].sharing_profile_id IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}
</foreach>
AND user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
</select>
@@ -123,4 +161,25 @@
WHERE sharing_profile_id = #{object.objectID,jdbcType=INTEGER}
</update>
</mapper>
<!-- Delete attributes associated with sharing profile -->
<delete id="deleteAttributes">
DELETE FROM [guacamole_sharing_profile_attribute]
WHERE sharing_profile_id = #{object.objectID,jdbcType=INTEGER}
</delete>
<!-- Insert attributes for sharing profile -->
<insert id="insertAttributes" parameterType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel">
INSERT INTO [guacamole_sharing_profile_attribute] (
sharing_profile_id,
attribute_name,
attribute_value
)
VALUES
<foreach collection="object.arbitraryAttributes" item="attribute" separator=",">
(#{object.objectID,jdbcType=INTEGER},
#{attribute.name,jdbcType=VARCHAR},
#{attribute.value,jdbcType=VARCHAR})
</foreach>
</insert>
</mapper>

View File

@@ -25,6 +25,8 @@
<!-- Result mapper for user objects -->
<resultMap id="UserResultMap" type="org.apache.guacamole.auth.jdbc.user.UserModel" >
<!-- User properties -->
<id column="user_id" property="objectID" jdbcType="INTEGER"/>
<result column="username" property="identifier" jdbcType="VARCHAR"/>
<result column="password_hash" property="passwordHash" jdbcType="BINARY"/>
@@ -42,6 +44,15 @@
<result column="organization" property="organization" jdbcType="VARCHAR"/>
<result column="organizational_role" property="organizationalRole" jdbcType="VARCHAR"/>
<result column="last_active" property="lastActive" jdbcType="TIMESTAMP"/>
<!-- Arbitrary attributes -->
<collection property="arbitraryAttributes" resultSet="arbitraryAttributes"
ofType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel"
column="user_id" foreignColumn="user_id">
<result property="name" column="attribute_name" jdbcType="VARCHAR"/>
<result property="value" column="attribute_value" jdbcType="VARCHAR"/>
</collection>
</resultMap>
<!-- Select all usernames -->
@@ -61,7 +72,8 @@
</select>
<!-- Select multiple users by username -->
<select id="select" resultMap="UserResultMap">
<select id="select" resultMap="UserResultMap"
resultSets="users,arbitraryAttributes">
SELECT
[guacamole_user].user_id,
@@ -92,10 +104,23 @@
#{identifier,jdbcType=VARCHAR}
</foreach>;
SELECT
[guacamole_user_attribute].user_id,
[guacamole_user_attribute].attribute_name,
[guacamole_user_attribute].attribute_value
FROM [guacamole_user_attribute]
JOIN [guacamole_user] ON [guacamole_user].user_id = [guacamole_user_attribute].user_id
WHERE username IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}
</foreach>;
</select>
<!-- Select multiple users by username only if readable -->
<select id="selectReadable" resultMap="UserResultMap">
<select id="selectReadable" resultMap="UserResultMap"
resultSets="users,arbitraryAttributes">
SELECT
[guacamole_user].user_id,
@@ -127,12 +152,28 @@
#{identifier,jdbcType=VARCHAR}
</foreach>
AND [guacamole_user_permission].user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ'
AND permission = 'READ';
SELECT
[guacamole_user_attribute].user_id,
[guacamole_user_attribute].attribute_name,
[guacamole_user_attribute].attribute_value
FROM [guacamole_user_attribute]
JOIN [guacamole_user] ON [guacamole_user].user_id = [guacamole_user_attribute].user_id
JOIN [guacamole_user_permission] ON affected_user_id = [guacamole_user].user_id
WHERE username IN
<foreach collection="identifiers" item="identifier"
open="(" separator="," close=")">
#{identifier,jdbcType=INTEGER}
</foreach>
AND [guacamole_user_permission].user_id = #{user.objectID,jdbcType=INTEGER}
AND permission = 'READ';
</select>
<!-- Select single user by username -->
<select id="selectOne" resultMap="UserResultMap">
<select id="selectOne" resultMap="UserResultMap"
resultSets="users,arbitraryAttributes">
SELECT
[guacamole_user].user_id,
@@ -159,7 +200,15 @@
FROM [guacamole_user]
LEFT JOIN [guacamole_user_history] ON [guacamole_user_history].user_id = [guacamole_user].user_id
WHERE
[guacamole_user].username = #{username,jdbcType=VARCHAR}
[guacamole_user].username = #{username,jdbcType=VARCHAR};
SELECT
[guacamole_user_attribute].user_id,
[guacamole_user_attribute].attribute_name,
[guacamole_user_attribute].attribute_value
FROM [guacamole_user_attribute]
JOIN [guacamole_user] ON [guacamole_user].user_id = [guacamole_user_attribute].user_id
WHERE username = #{username,jdbcType=VARCHAR};
</select>
@@ -230,4 +279,25 @@
WHERE user_id = #{object.objectID,jdbcType=VARCHAR}
</update>
<!-- Delete attributes associated with user -->
<delete id="deleteAttributes">
DELETE FROM [guacamole_user_attribute]
WHERE user_id = #{object.objectID,jdbcType=INTEGER}
</delete>
<!-- Insert attributes for user -->
<insert id="insertAttributes" parameterType="org.apache.guacamole.auth.jdbc.base.ArbitraryAttributeModel">
INSERT INTO [guacamole_user_attribute] (
user_id,
attribute_name,
attribute_value
)
VALUES
<foreach collection="object.arbitraryAttributes" item="attribute" separator=",">
(#{object.objectID,jdbcType=INTEGER},
#{attribute.name,jdbcType=VARCHAR},
#{attribute.value,jdbcType=VARCHAR})
</foreach>
</insert>
</mapper>

View File

@@ -0,0 +1,59 @@
/*
* 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.net.auth;
import java.util.Map;
/**
* An object which is associated with a set of arbitrary attributes, defined
* as name/value pairs.
*/
public interface Attributes {
/**
* Returns all attributes associated with this object. The returned map
* may not be modifiable.
*
* @return
* A map of all attribute identifiers to their corresponding values,
* for all attributes associated with this object, which may not be
* modifiable.
*/
Map<String, String> getAttributes();
/**
* Sets the given attributes. If an attribute within the map is not
* supported, it will simply be dropped. Any attributes not within the given
* map will be left untouched. Attributes which are not declared within the
* associated UserContext MUST NOT be submitted, but other extensions may
* manipulate the declared attributes through decorate() and redecorate().
*
* Implementations may optionally allow storage of unsupported attributes.
* Extensions which rely on other extensions to store their attribute
* values should verify that such storage is supported by first testing
* that the attribute value is retrievable via getAttributes() after being
* set.
*
* @param attributes
* A map of all attribute identifiers to their corresponding values.
*/
void setAttributes(Map<String, String> attributes);
}

View File

@@ -21,7 +21,6 @@ package org.apache.guacamole.net.auth;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.protocol.GuacamoleConfiguration;
@@ -32,7 +31,7 @@ import org.apache.guacamole.protocol.GuacamoleConfiguration;
* backing GuacamoleConfiguration may be intentionally obfuscated or tokenized
* to protect sensitive configuration information.
*/
public interface Connection extends Identifiable, Connectable {
public interface Connection extends Identifiable, Connectable, Attributes {
/**
* Returns the name assigned to this Connection.
@@ -82,27 +81,6 @@ public interface Connection extends Identifiable, Connectable {
*/
public void setConfiguration(GuacamoleConfiguration config);
/**
* Returns all attributes associated with this connection. The returned map
* may not be modifiable.
*
* @return
* A map of all attribute identifiers to their corresponding values,
* for all attributes associated with this connection, which may not be
* modifiable.
*/
Map<String, String> getAttributes();
/**
* Sets the given attributes. If an attribute within the map is not
* supported, it will simply be dropped. Any attributes not within the
* given map will be left untouched.
*
* @param attributes
* A map of all attribute identifiers to their corresponding values.
*/
void setAttributes(Map<String, String> attributes);
/**
* Returns the date and time that this connection was last used. If the
* connection was never used, the time that the connection was last used is

View File

@@ -19,7 +19,6 @@
package org.apache.guacamole.net.auth;
import java.util.Map;
import java.util.Set;
import org.apache.guacamole.GuacamoleException;
@@ -27,7 +26,7 @@ import org.apache.guacamole.GuacamoleException;
* Represents a connection group, which can contain both other connection groups
* as well as connections.
*/
public interface ConnectionGroup extends Identifiable, Connectable {
public interface ConnectionGroup extends Identifiable, Connectable, Attributes {
/**
* All legal types of connection group.
@@ -124,25 +123,4 @@ public interface ConnectionGroup extends Identifiable, Connectable {
public Set<String> getConnectionGroupIdentifiers()
throws GuacamoleException;
/**
* Returns all attributes associated with this connection group. The
* returned map may not be modifiable.
*
* @return
* A map of all attribute identifiers to their corresponding values,
* for all attributes associated with this connection group, which may
* not be modifiable.
*/
Map<String, String> getAttributes();
/**
* Sets the given attributes. If an attribute within the map is not
* supported, it will simply be dropped. Any attributes not within the
* given map will be left untouched.
*
* @param attributes
* A map of all attribute identifiers to their corresponding values.
*/
void setAttributes(Map<String, String> attributes);
}

View File

@@ -25,7 +25,7 @@ import java.util.Map;
* Represents the semantics which apply to an existing connection when shared,
* along with a human-readable name and unique identifier.
*/
public interface SharingProfile extends Identifiable {
public interface SharingProfile extends Identifiable, Attributes {
/**
* Returns the human-readable name assigned to this SharingProfile.
@@ -93,25 +93,4 @@ public interface SharingProfile extends Identifiable {
*/
public void setParameters(Map<String, String> parameters);
/**
* Returns all attributes associated with this sharing profile. The returned
* map may not be modifiable.
*
* @return
* A map of all attribute identifiers to their corresponding values,
* for all attributes associated with this sharing profile, which may
* not be modifiable.
*/
Map<String, String> getAttributes();
/**
* Sets the given attributes. If an attribute within the map is not
* supported, it will simply be dropped. Any attributes not within the
* given map will be left untouched.
*
* @param attributes
* A map of all attribute identifiers to their corresponding values.
*/
void setAttributes(Map<String, String> attributes);
}

View File

@@ -21,7 +21,6 @@ package org.apache.guacamole.net.auth;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
@@ -30,7 +29,7 @@ import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
/**
* A user of the Guacamole web application.
*/
public interface User extends Identifiable {
public interface User extends Identifiable, Attributes {
/**
* All standard attribute names with semantics defined by the Guacamole web
@@ -81,27 +80,6 @@ public interface User extends Identifiable {
*/
public void setPassword(String password);
/**
* Returns all attributes associated with this user. The returned map may
* not be modifiable.
*
* @return
* A map of all attribute identifiers to their corresponding values,
* for all attributes associated with this user, which may not be
* modifiable.
*/
Map<String, String> getAttributes();
/**
* Sets the given attributes. If an attribute within the map is not
* supported, it will simply be dropped. Any attributes not within the
* given map will be left untouched.
*
* @param attributes
* A map of all attribute identifiers to their corresponding values.
*/
void setAttributes(Map<String, String> attributes);
/**
* Returns the date and time that this user was last active. If the user
* was never active, the time that the user was last active is unknown, or

View File

@@ -22,6 +22,7 @@ package org.apache.guacamole.rest.activeconnection;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.net.auth.ActiveConnection;
import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
/**
@@ -30,7 +31,7 @@ import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
* toExternalObject() is implemented here.
*/
public class ActiveConnectionObjectTranslator
implements DirectoryObjectTranslator<ActiveConnection, APIActiveConnection> {
extends DirectoryObjectTranslator<ActiveConnection, APIActiveConnection> {
@Override
public APIActiveConnection toExternalObject(ActiveConnection object)
@@ -56,4 +57,10 @@ public class ActiveConnectionObjectTranslator
}
@Override
public void filterExternalObject(UserContext context,
APIActiveConnection object) throws GuacamoleException {
// Nothing to filter on ActiveConnections (no attributes)
}
}

View File

@@ -89,7 +89,7 @@ public class ActiveConnectionResource
@Assisted Directory<ActiveConnection> directory,
@Assisted ActiveConnection activeConnection,
DirectoryObjectTranslator<ActiveConnection, APIActiveConnection> translator) {
super(directory, activeConnection, translator);
super(userContext, directory, activeConnection, translator);
this.userContext = userContext;
this.activeConnection = activeConnection;
}

View File

@@ -21,6 +21,7 @@ package org.apache.guacamole.rest.connection;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.Connection;
import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.protocol.GuacamoleConfiguration;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
@@ -29,7 +30,7 @@ import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
* objects.
*/
public class ConnectionObjectTranslator
implements DirectoryObjectTranslator<Connection, APIConnection> {
extends DirectoryObjectTranslator<Connection, APIConnection> {
@Override
public APIConnection toExternalObject(Connection object)
@@ -59,4 +60,14 @@ public class ConnectionObjectTranslator
}
@Override
public void filterExternalObject(UserContext userContext,
APIConnection object) throws GuacamoleException {
// Filter object attributes by defined schema
object.setAttributes(filterAttributes(
userContext.getConnectionAttributes(), object.getAttributes()));
}
}

View File

@@ -100,7 +100,7 @@ public class ConnectionResource extends DirectoryObjectResource<Connection, APIC
@Assisted Directory<Connection> directory,
@Assisted Connection connection,
DirectoryObjectTranslator<Connection, APIConnection> translator) {
super(directory, connection, translator);
super(userContext, directory, connection, translator);
this.userContext = userContext;
this.connection = connection;
}

View File

@@ -21,6 +21,7 @@ package org.apache.guacamole.rest.connectiongroup;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.ConnectionGroup;
import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
/**
@@ -28,7 +29,7 @@ import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
* APIConnectionGroup objects.
*/
public class ConnectionGroupObjectTranslator
implements DirectoryObjectTranslator<ConnectionGroup, APIConnectionGroup> {
extends DirectoryObjectTranslator<ConnectionGroup, APIConnectionGroup> {
@Override
public APIConnectionGroup toExternalObject(ConnectionGroup object)
@@ -53,4 +54,15 @@ public class ConnectionGroupObjectTranslator
}
@Override
public void filterExternalObject(UserContext userContext,
APIConnectionGroup object) throws GuacamoleException {
// Filter object attributes by defined schema
object.setAttributes(filterAttributes(
userContext.getConnectionGroupAttributes(),
object.getAttributes()));
}
}

View File

@@ -79,7 +79,7 @@ public class ConnectionGroupResource
@Assisted Directory<ConnectionGroup> directory,
@Assisted ConnectionGroup connectionGroup,
DirectoryObjectTranslator<ConnectionGroup, APIConnectionGroup> translator) {
super(directory, connectionGroup, translator);
super(userContext, directory, connectionGroup, translator);
this.userContext = userContext;
this.connectionGroup = connectionGroup;
}

View File

@@ -29,6 +29,7 @@ import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.Identifiable;
import org.apache.guacamole.net.auth.UserContext;
/**
* A REST resource which abstracts the operations available on an existing
@@ -50,6 +51,12 @@ import org.apache.guacamole.net.auth.Identifiable;
@Consumes(MediaType.APPLICATION_JSON)
public abstract class DirectoryObjectResource<InternalType extends Identifiable, ExternalType> {
/**
* The UserContext associated with the Directory containing the object
* represented by this DirectoryObjectResource.
*/
private final UserContext userContext;
/**
* The Directory which contains the object represented by this
* DirectoryObjectResource.
@@ -71,6 +78,9 @@ public abstract class DirectoryObjectResource<InternalType extends Identifiable,
* Creates a new DirectoryObjectResource which exposes the operations
* available for the given object.
*
* @param userContext
* The UserContext associated with the given Directory.
*
* @param directory
* The Directory which contains the given object.
*
@@ -81,8 +91,10 @@ public abstract class DirectoryObjectResource<InternalType extends Identifiable,
* A DirectoryObjectTranslator implementation which handles the type of
* object given.
*/
public DirectoryObjectResource(Directory<InternalType> directory, InternalType object,
public DirectoryObjectResource(UserContext userContext,
Directory<InternalType> directory, InternalType object,
DirectoryObjectTranslator<InternalType, ExternalType> translator) {
this.userContext = userContext;
this.directory = directory;
this.object = object;
this.translator = translator;
@@ -121,6 +133,9 @@ public abstract class DirectoryObjectResource<InternalType extends Identifiable,
if (modifiedObject == null)
throw new GuacamoleClientException("Data must be submitted when updating objects.");
// Filter/sanitize object contents
translator.filterExternalObject(userContext, modifiedObject);
// Perform update
translator.applyExternalChanges(object, modifiedObject);
directory.update(object);

View File

@@ -19,8 +19,14 @@
package org.apache.guacamole.rest.directory;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.form.Field;
import org.apache.guacamole.form.Form;
import org.apache.guacamole.net.auth.Identifiable;
import org.apache.guacamole.net.auth.UserContext;
/**
* Provides bidirectional conversion between REST-specific objects and the
@@ -35,7 +41,7 @@ import org.apache.guacamole.net.auth.Identifiable;
* deserialized as JSON) between REST clients and resource implementations
* when representing the InternalType.
*/
public interface DirectoryObjectTranslator<InternalType extends Identifiable, ExternalType> {
public abstract class DirectoryObjectTranslator<InternalType extends Identifiable, ExternalType> {
/**
* Converts the given object to an object which is intended to be used in
@@ -51,7 +57,7 @@ public interface DirectoryObjectTranslator<InternalType extends Identifiable, Ex
* @throws GuacamoleException
* If the provided object cannot be converted for any reason.
*/
ExternalType toExternalObject(InternalType object)
public abstract ExternalType toExternalObject(InternalType object)
throws GuacamoleException;
/**
@@ -69,7 +75,7 @@ public interface DirectoryObjectTranslator<InternalType extends Identifiable, Ex
* @throws GuacamoleException
* If the provided object cannot be converted for any reason.
*/
InternalType toInternalObject(ExternalType object)
public abstract InternalType toInternalObject(ExternalType object)
throws GuacamoleException;
/**
@@ -87,7 +93,67 @@ public interface DirectoryObjectTranslator<InternalType extends Identifiable, Ex
* @throws GuacamoleException
* If the provided modifications cannot be applied for any reason.
*/
void applyExternalChanges(InternalType existingObject, ExternalType object)
throws GuacamoleException;
public abstract void applyExternalChanges(InternalType existingObject,
ExternalType object) throws GuacamoleException;
/**
* Applies filtering to the contents of the given external object which
* came from an untrusted source. Implementations MUST sanitize the
* contents of the external object as necessary to guarantee that the
* object conforms to declared schema, such as the attributes declared for
* each object type at the UserContext level.
*
* @param userContext
* The UserContext associated with the object being filtered.
*
* @param object
* The object to modify such that it strictly conforms to the declared
* schema.
*
* @throws GuacamoleException
* If the object cannot be filtered due to an error.
*/
public abstract void filterExternalObject(UserContext userContext,
ExternalType object) throws GuacamoleException;
/**
* Filters the given map of attribute name/value pairs, producing a new
* map containing only attributes defined as fields within the given schema.
*
* @param schema
* The schema whose fields should be used to filter the given map of
* attributes.
*
* @param attributes
* The map of attribute name/value pairs to filter.
*
* @return
* A new map containing only the attributes defined as fields within
* the given schema.
*/
public Map<String, String> filterAttributes(Collection<Form> schema,
Map<String, String> attributes) {
Map<String, String> filtered = new HashMap<String, String>();
// Grab all attribute value strictly for defined fields
for (Form form : schema) {
for (Field field : form.getFields()) {
// Pull the associated attribute value from given map
String attributeName = field.getName();
String attributeValue = attributes.get(attributeName);
// Include attribute value within filtered map only if
// (1) defined and (2) present within provided map
if (attributeValue != null)
filtered.put(attributeName, attributeValue);
}
}
return filtered;
}
}

View File

@@ -222,6 +222,9 @@ public abstract class DirectoryResource<InternalType extends Identifiable, Exter
if (object == null)
throw new GuacamoleClientException("Data must be submitted when creating objects.");
// Filter/sanitize object contents
translator.filterExternalObject(userContext, object);
// Create the new object within the directory
directory.add(translator.toInternalObject(object));

View File

@@ -21,6 +21,7 @@ package org.apache.guacamole.rest.sharingprofile;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.SharingProfile;
import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
/**
@@ -28,7 +29,7 @@ import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
* APISharingProfile objects.
*/
public class SharingProfileObjectTranslator
implements DirectoryObjectTranslator<SharingProfile, APISharingProfile> {
extends DirectoryObjectTranslator<SharingProfile, APISharingProfile> {
@Override
public APISharingProfile toExternalObject(SharingProfile object)
@@ -53,4 +54,15 @@ public class SharingProfileObjectTranslator
}
@Override
public void filterExternalObject(UserContext userContext,
APISharingProfile object) throws GuacamoleException {
// Filter object attributes by defined schema
object.setAttributes(filterAttributes(
userContext.getSharingProfileAttributes(),
object.getAttributes()));
}
}

View File

@@ -82,7 +82,7 @@ public class SharingProfileResource
@Assisted Directory<SharingProfile> directory,
@Assisted SharingProfile sharingProfile,
DirectoryObjectTranslator<SharingProfile, APISharingProfile> translator) {
super(directory, sharingProfile, translator);
super(userContext, directory, sharingProfile, translator);
this.userContext = userContext;
this.sharingProfile = sharingProfile;
}

View File

@@ -21,13 +21,14 @@ package org.apache.guacamole.rest.user;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.User;
import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.rest.directory.DirectoryObjectTranslator;
/**
* Translator which converts between User objects and APIUser objects.
*/
public class UserObjectTranslator
implements DirectoryObjectTranslator<User, APIUser> {
extends DirectoryObjectTranslator<User, APIUser> {
@Override
public APIUser toExternalObject(User object)
@@ -54,4 +55,14 @@ public class UserObjectTranslator
}
@Override
public void filterExternalObject(UserContext userContext, APIUser object)
throws GuacamoleException {
// Filter object attributes by defined schema
object.setAttributes(filterAttributes(userContext.getUserAttributes(),
object.getAttributes()));
}
}

View File

@@ -92,7 +92,7 @@ public class UserResource
@Assisted Directory<User> directory,
@Assisted User user,
DirectoryObjectTranslator<User, APIUser> translator) {
super(directory, user, translator);
super(userContext, directory, user, translator);
this.userContext = userContext;
this.directory = directory;
this.user = user;