From 77255652bf532b8f28baf687a6bfb10979cfa266 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sun, 29 Oct 2017 12:59:50 -0700 Subject: [PATCH 1/9] GUACAMOLE-96: Restrict submitted attributes to those explicitly declared by the UserContext. --- .../ActiveConnectionObjectTranslator.java | 9 ++- .../ActiveConnectionResource.java | 2 +- .../ConnectionObjectTranslator.java | 13 +++- .../rest/connection/ConnectionResource.java | 2 +- .../ConnectionGroupObjectTranslator.java | 14 +++- .../ConnectionGroupResource.java | 2 +- .../directory/DirectoryObjectResource.java | 17 ++++- .../directory/DirectoryObjectTranslator.java | 76 +++++++++++++++++-- .../rest/directory/DirectoryResource.java | 3 + .../SharingProfileObjectTranslator.java | 14 +++- .../SharingProfileResource.java | 2 +- .../rest/user/UserObjectTranslator.java | 13 +++- .../guacamole/rest/user/UserResource.java | 2 +- 13 files changed, 153 insertions(+), 16 deletions(-) diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionObjectTranslator.java b/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionObjectTranslator.java index d59f8c52c..712a82f62 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionObjectTranslator.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionObjectTranslator.java @@ -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 { + extends DirectoryObjectTranslator { @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) + } + } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionResource.java index e72e674a3..47ba3d42b 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/activeconnection/ActiveConnectionResource.java @@ -89,7 +89,7 @@ public class ActiveConnectionResource @Assisted Directory directory, @Assisted ActiveConnection activeConnection, DirectoryObjectTranslator translator) { - super(directory, activeConnection, translator); + super(userContext, directory, activeConnection, translator); this.userContext = userContext; this.activeConnection = activeConnection; } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/connection/ConnectionObjectTranslator.java b/guacamole/src/main/java/org/apache/guacamole/rest/connection/ConnectionObjectTranslator.java index 112c71aa2..416fb4a63 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/connection/ConnectionObjectTranslator.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/connection/ConnectionObjectTranslator.java @@ -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 { + extends DirectoryObjectTranslator { @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())); + + } + } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/connection/ConnectionResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/connection/ConnectionResource.java index b1ddcfc47..0b63b66e5 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/connection/ConnectionResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/connection/ConnectionResource.java @@ -100,7 +100,7 @@ public class ConnectionResource extends DirectoryObjectResource directory, @Assisted Connection connection, DirectoryObjectTranslator translator) { - super(directory, connection, translator); + super(userContext, directory, connection, translator); this.userContext = userContext; this.connection = connection; } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupObjectTranslator.java b/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupObjectTranslator.java index 18de4dc0e..3c0ed38d6 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupObjectTranslator.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupObjectTranslator.java @@ -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 { + extends DirectoryObjectTranslator { @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())); + + } + } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupResource.java index 9e7c9866a..f91b8ebb9 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/connectiongroup/ConnectionGroupResource.java @@ -79,7 +79,7 @@ public class ConnectionGroupResource @Assisted Directory directory, @Assisted ConnectionGroup connectionGroup, DirectoryObjectTranslator translator) { - super(directory, connectionGroup, translator); + super(userContext, directory, connectionGroup, translator); this.userContext = userContext; this.connectionGroup = connectionGroup; } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryObjectResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryObjectResource.java index b5277b3f9..7b354a226 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryObjectResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryObjectResource.java @@ -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 { + /** + * 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 directory, InternalType object, + public DirectoryObjectResource(UserContext userContext, + Directory directory, InternalType object, DirectoryObjectTranslator translator) { + this.userContext = userContext; this.directory = directory; this.object = object; this.translator = translator; @@ -121,6 +133,9 @@ public abstract class DirectoryObjectResource { +public abstract class DirectoryObjectTranslator { /** * Converts the given object to an object which is intended to be used in @@ -51,7 +57,7 @@ public interface DirectoryObjectTranslator filterAttributes(Collection
schema, + Map attributes) { + + Map filtered = new HashMap(); + + // 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; + + } } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryResource.java index 2af0e26df..3cbd4817d 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/directory/DirectoryResource.java @@ -222,6 +222,9 @@ public abstract class DirectoryResource { + extends DirectoryObjectTranslator { @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())); + + } + } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/sharingprofile/SharingProfileResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/sharingprofile/SharingProfileResource.java index 1f18d0f94..7b96de904 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/sharingprofile/SharingProfileResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/sharingprofile/SharingProfileResource.java @@ -82,7 +82,7 @@ public class SharingProfileResource @Assisted Directory directory, @Assisted SharingProfile sharingProfile, DirectoryObjectTranslator translator) { - super(directory, sharingProfile, translator); + super(userContext, directory, sharingProfile, translator); this.userContext = userContext; this.sharingProfile = sharingProfile; } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/user/UserObjectTranslator.java b/guacamole/src/main/java/org/apache/guacamole/rest/user/UserObjectTranslator.java index 35bce6681..8536b3507 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/user/UserObjectTranslator.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/user/UserObjectTranslator.java @@ -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 { + extends DirectoryObjectTranslator { @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())); + + } + } diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/user/UserResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/user/UserResource.java index 75a49dbbf..06bab9f43 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/user/UserResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/user/UserResource.java @@ -92,7 +92,7 @@ public class UserResource @Assisted Directory directory, @Assisted User user, DirectoryObjectTranslator translator) { - super(directory, user, translator); + super(userContext, directory, user, translator); this.userContext = userContext; this.directory = directory; this.user = user; From 79936c4c419e602a824376a933661590e593a9c9 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sun, 29 Oct 2017 13:09:45 -0700 Subject: [PATCH 2/9] GUACAMOLE-96: Document semantics of voluntary attribute storage and guaranteed sanitization. --- .../org/apache/guacamole/net/auth/Connection.java | 13 +++++++++++-- .../apache/guacamole/net/auth/ConnectionGroup.java | 13 +++++++++++-- .../apache/guacamole/net/auth/SharingProfile.java | 11 ++++++++++- .../java/org/apache/guacamole/net/auth/User.java | 13 +++++++++++-- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Connection.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Connection.java index 85fd1680d..313d89e20 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Connection.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Connection.java @@ -95,8 +95,17 @@ public interface Connection extends Identifiable, Connectable { /** * 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. + * supported, it will simply be dropped. Any attributes not within the given + * map will be left untouched. Attributes which are not declared within + * getConnectionAttributes() of 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. diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/ConnectionGroup.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/ConnectionGroup.java index 8e34e416a..04b494a90 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/ConnectionGroup.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/ConnectionGroup.java @@ -137,8 +137,17 @@ public interface ConnectionGroup extends Identifiable, Connectable { /** * 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. + * supported, it will simply be dropped. Any attributes not within the given + * map will be left untouched. Attributes which are not declared within + * getConnectionGroupAttributes() of 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. diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/SharingProfile.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/SharingProfile.java index f9ec34c84..3b4ec6570 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/SharingProfile.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/SharingProfile.java @@ -107,7 +107,16 @@ public interface SharingProfile extends Identifiable { /** * 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. + * given map will be left untouched. Attributes which are not declared + * within getSharingProfileAttributes() of 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. diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/User.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/User.java index f7bd61ca2..49e1f9923 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/User.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/User.java @@ -94,8 +94,17 @@ public interface User extends Identifiable { /** * 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. + * supported, it will simply be dropped. Any attributes not within the given + * map will be left untouched. Attributes which are not declared within + * getUserAttributes() of 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. From fff14117681d333c6b93fa274235df7c3ddb25ee Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sun, 29 Oct 2017 15:33:10 -0700 Subject: [PATCH 3/9] GUACAMOLE-96: Extract Attributes interface from objects which provide getAttributes() / setAttributes(). --- .../apache/guacamole/net/auth/Attributes.java | 59 +++++++++++++++++++ .../apache/guacamole/net/auth/Connection.java | 33 +---------- .../guacamole/net/auth/ConnectionGroup.java | 33 +---------- .../guacamole/net/auth/SharingProfile.java | 32 +--------- .../org/apache/guacamole/net/auth/User.java | 33 +---------- 5 files changed, 63 insertions(+), 127 deletions(-) create mode 100644 guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Attributes.java diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Attributes.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Attributes.java new file mode 100644 index 000000000..050017dd7 --- /dev/null +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Attributes.java @@ -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 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 attributes); + +} diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Connection.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Connection.java index 313d89e20..5b1d13d54 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Connection.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/Connection.java @@ -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,36 +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 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 - * getConnectionAttributes() of 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 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 diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/ConnectionGroup.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/ConnectionGroup.java index 04b494a90..74412de7d 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/ConnectionGroup.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/ConnectionGroup.java @@ -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,34 +123,4 @@ public interface ConnectionGroup extends Identifiable, Connectable { public Set 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 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 - * getConnectionGroupAttributes() of 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 attributes); - } diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/SharingProfile.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/SharingProfile.java index 3b4ec6570..2d4c4326a 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/SharingProfile.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/SharingProfile.java @@ -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,34 +93,4 @@ public interface SharingProfile extends Identifiable { */ public void setParameters(Map 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 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 getSharingProfileAttributes() of 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 attributes); - } diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/User.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/User.java index 49e1f9923..a39a772f0 100644 --- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/User.java +++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/User.java @@ -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,36 +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 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 - * getUserAttributes() of 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 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 From a3cee158cb771582dc9e7172cf8b3428204600ff Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 18 Nov 2017 16:42:13 -0800 Subject: [PATCH 4/9] GUACAMOLE-96: Add object- and model-level support for storage of arbitrary attributes. --- .../jdbc/base/ModeledDirectoryObject.java | 57 ++++++++++++++++++- .../guacamole/auth/jdbc/base/ObjectModel.java | 41 ++++++++++++- .../jdbc/connection/ModeledConnection.java | 28 ++++++++- .../ModeledConnectionGroup.java | 24 +++++++- .../sharingprofile/ModeledSharingProfile.java | 10 ---- .../guacamole/auth/jdbc/user/ModeledUser.java | 33 ++++++++++- 6 files changed, 175 insertions(+), 18 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObject.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObject.java index 0d15373c4..e13445bc7 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObject.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObject.java @@ -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 - extends ModeledObject implements Identifiable { + extends ModeledObject implements Identifiable, Attributes { @Override public String getIdentifier() { @@ -43,4 +48,54 @@ public abstract class ModeledDirectoryObject 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 getSupportedAttributeNames() { + return Collections.emptySet(); + } + + @Override + public Map getAttributes() { + + // If no arbitrary attributes are defined, just return an empty map + Map arbitraryAttributes = getModel().getArbitraryAttributes(); + if (arbitraryAttributes == null) + return new HashMap(); + + // Otherwise include any defined arbitrary attributes + return new HashMap(arbitraryAttributes); + + } + + @Override + public void setAttributes(Map attributes) { + + // Get set of all supported attribute names + Set supportedAttributes = getSupportedAttributeNames(); + + // Initialize model with empty map if no such map is already present + Map arbitraryAttributes = getModel().getArbitraryAttributes(); + if (arbitraryAttributes == null) { + arbitraryAttributes = new HashMap(); + getModel().setArbitraryAttributes(arbitraryAttributes); + } + + // Store remaining attributes only if not directly mapped to model + for (Map.Entry attribute : attributes.entrySet()) { + String name = attribute.getKey(); + if (!supportedAttributes.contains(name)) + arbitraryAttributes.put(name, attribute.getValue()); + } + + } + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ObjectModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ObjectModel.java index 833c0d993..3841f6f3e 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ObjectModel.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ObjectModel.java @@ -19,6 +19,8 @@ package org.apache.guacamole.auth.jdbc.base; +import java.util.Map; + /** * Object representation of a Guacamole object, such as a user or connection, * as represented in the database. @@ -34,7 +36,13 @@ 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 Map arbitraryAttributes; + /** * Creates a new, empty object. */ @@ -82,4 +90,35 @@ 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 Map getArbitraryAttributes() { + return arbitraryAttributes; + } + + /** + * Sets all arbitrary attribute name/value pairs associated with this + * model. The provided map should contain only attributes which are not + * explicitly supported by the model, as any explicitly-supported + * attributes should instead be mapped to corresponding properties. + * + * @param arbitraryAttributes + * A map of attribute name/value pairs for all attributes associated + * with this model which do not otherwise have explicit mappings to + * properties. + */ + public void setArbitraryAttributes(Map arbitraryAttributes) { + this.arbitraryAttributes = arbitraryAttributes; + } + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnection.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnection.java index eb392bc7b..660212cdc 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnection.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnection.java @@ -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 ATTRIBUTE_NAMES = + Collections.unmodifiableSet(new HashSet(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 getSupportedAttributeNames() { + return ATTRIBUTE_NAMES; + } + @Override public Map getAttributes() { - Map attributes = new HashMap(); + // Include any defined arbitrary attributes + Map 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 attributes) { + // Set arbitrary attributes + super.setAttributes(attributes); + // Translate connection limit attribute try { getModel().setMaxConnections(NumericField.parse(attributes.get(MAX_CONNECTIONS_NAME))); } catch (NumberFormatException e) { diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ModeledConnectionGroup.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ModeledConnectionGroup.java index 7e65c7f75..3aac52d59 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ModeledConnectionGroup.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connectiongroup/ModeledConnectionGroup.java @@ -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 ATTRIBUTE_NAMES = + Collections.unmodifiableSet(new HashSet(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 getSupportedAttributeNames() { + return ATTRIBUTE_NAMES; + } + @Override public Map getAttributes() { - Map attributes = new HashMap(); + // Include any defined arbitrary attributes + Map 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 attributes) { + // Set arbitrary attributes + super.setAttributes(attributes); + // Translate connection limit attribute try { getModel().setMaxConnections(NumericField.parse(attributes.get(MAX_CONNECTIONS_NAME))); } catch (NumberFormatException e) { diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharingprofile/ModeledSharingProfile.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharingprofile/ModeledSharingProfile.java index 19c70bb7e..1acbd790f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharingprofile/ModeledSharingProfile.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/sharingprofile/ModeledSharingProfile.java @@ -95,14 +95,4 @@ public class ModeledSharingProfile this.parameters = parameters; } - @Override - public Map getAttributes() { - return Collections.emptyMap(); - } - - @Override - public void setAttributes(Map attributes) { - // Do nothing - no attributes - } - } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java index 5ffc458e5..b29565551 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/user/ModeledUser.java @@ -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 implements Us ACCOUNT_RESTRICTIONS )); + /** + * The names of all attributes which are explicitly supported by this + * extension's User objects. + */ + public static final Set ATTRIBUTE_NAMES = + Collections.unmodifiableSet(new HashSet(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 implements Us } + @Override + public Set getSupportedAttributeNames() { + return ATTRIBUTE_NAMES; + } + @Override public Map getAttributes() { - Map attributes = new HashMap(); + // Include any defined arbitrary attributes + Map attributes = super.getAttributes(); // Always include unrestricted attributes putUnrestrictedAttributes(attributes); @@ -565,6 +591,9 @@ public class ModeledUser extends ModeledDirectoryObject implements Us @Override public void setAttributes(Map attributes) { + // Set arbitrary attributes + super.setAttributes(attributes); + // Always assign unrestricted attributes setUnrestrictedAttributes(attributes); From b6de402c0c1fbcaa2d6e95ebbc99baef9165bbe9 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 22 Nov 2017 12:29:58 -0800 Subject: [PATCH 5/9] GUACAMOLE-96: Add base support within JDBC auth for storage of arbitrary attributes from other extensions. --- .../auth/jdbc/base/ArbitraryAttributeMap.java | 162 ++++++++++++++++++ .../jdbc/base/ArbitraryAttributeModel.java | 104 +++++++++++ .../jdbc/base/ModeledDirectoryObject.java | 33 ++-- .../base/ModeledDirectoryObjectMapper.java | 25 ++- .../base/ModeledDirectoryObjectService.java | 12 ++ .../guacamole/auth/jdbc/base/ObjectModel.java | 49 ++++-- 6 files changed, 354 insertions(+), 31 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ArbitraryAttributeMap.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ArbitraryAttributeModel.java diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ArbitraryAttributeMap.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ArbitraryAttributeMap.java new file mode 100644 index 000000000..e2cb43805 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ArbitraryAttributeMap.java @@ -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 { + + /** + * 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 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 toModelCollection() { + return new AbstractCollection() { + + @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 iterator() { + + // Get iterator over all string name/value entries + final Iterator> iterator = entrySet().iterator(); + + // Dynamically translate each string name/value entry into a + // corresponding attribute model object as iteration continues + return new Iterator() { + + @Override + public boolean hasNext() { + return iterator.hasNext(); + } + + @Override + public ArbitraryAttributeModel next() { + Entry entry = iterator.next(); + return new ArbitraryAttributeModel(entry.getKey(), + entry.getValue()); + } + + }; + + } + + @Override + public int size() { + return ArbitraryAttributeMap.this.size(); + } + + }; + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ArbitraryAttributeModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ArbitraryAttributeModel.java new file mode 100644 index 000000000..b064b5414 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ArbitraryAttributeModel.java @@ -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; + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObject.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObject.java index e13445bc7..ddeda92a6 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObject.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObject.java @@ -65,35 +65,32 @@ public abstract class ModeledDirectoryObject @Override public Map getAttributes() { - - // If no arbitrary attributes are defined, just return an empty map - Map arbitraryAttributes = getModel().getArbitraryAttributes(); - if (arbitraryAttributes == null) - return new HashMap(); - - // Otherwise include any defined arbitrary attributes - return new HashMap(arbitraryAttributes); - + return new HashMap(getModel().getArbitraryAttributeMap()); } @Override public void setAttributes(Map attributes) { + ArbitraryAttributeMap arbitraryAttributes = getModel().getArbitraryAttributeMap(); + // Get set of all supported attribute names Set supportedAttributes = getSupportedAttributeNames(); - // Initialize model with empty map if no such map is already present - Map arbitraryAttributes = getModel().getArbitraryAttributes(); - if (arbitraryAttributes == null) { - arbitraryAttributes = new HashMap(); - getModel().setArbitraryAttributes(arbitraryAttributes); - } - // Store remaining attributes only if not directly mapped to model for (Map.Entry attribute : attributes.entrySet()) { + String name = attribute.getKey(); - if (!supportedAttributes.contains(name)) - arbitraryAttributes.put(name, attribute.getValue()); + String value = attribute.getValue(); + + // Handle null attributes as explicit removal of that attribute, + // as the underlying model cannot store null attribute values + if (!supportedAttributes.contains(name)) { + if (value == null) + arbitraryAttributes.remove(name); + else + arbitraryAttributes.put(name, value); + } + } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectMapper.java index ebd95d905..4431e8f42 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectMapper.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectMapper.java @@ -132,5 +132,28 @@ public interface ModeledDirectoryObjectMapper { * 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); + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java index 2c1402eb6..21508c471 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java @@ -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 arbitraryAttributes; + private ArbitraryAttributeMap arbitraryAttributes = + new ArbitraryAttributeMap(); /** * Creates a new, empty object. @@ -102,23 +103,47 @@ public abstract class ObjectModel { * with this model which do not otherwise have explicit mappings to * properties. */ - public Map getArbitraryAttributes() { + public ArbitraryAttributeMap getArbitraryAttributeMap() { return arbitraryAttributes; } /** - * Sets all arbitrary attribute name/value pairs associated with this - * model. The provided map should contain only attributes which are not - * explicitly supported by the model, as any explicitly-supported - * attributes should instead be mapped to corresponding properties. + * Returns whether at least one arbitrary attribute name/value pair has + * been associated with this object. + * + * @return + * true if this object has at least one arbitrary attribute set, false + * otherwise. + */ + public boolean hasArbitraryAttributes() { + return !arbitraryAttributes.isEmpty(); + } + + /** + * Returns a Collection view of the equivalent attribute model objects + * which make up the map of arbitrary attribute name/value pairs returned + * by getArbitraryAttributeMap(). Additions and removals on the returned + * Collection directly affect the attribute map. + * + * @return + * A Collection view of the map returned by + * getArbitraryAttributeMap(). + */ + public Collection getArbitraryAttributes() { + return arbitraryAttributes.toModelCollection(); + } + + /** + * Replaces all arbitrary attributes associated with this object with the + * attribute name/value pairs within the given collection of model objects. * * @param arbitraryAttributes - * A map of attribute name/value pairs for all attributes associated - * with this model which do not otherwise have explicit mappings to - * properties. + * The Collection of model objects containing the attribute name/value + * pairs which should replace all currently-stored arbitrary attributes, + * if any. */ - public void setArbitraryAttributes(Map arbitraryAttributes) { - this.arbitraryAttributes = arbitraryAttributes; + public void setArbitraryAttributes(Collection arbitraryAttributes) { + this.arbitraryAttributes = ArbitraryAttributeMap.fromModelCollection(arbitraryAttributes); } } From 494733569f3b39ff0f73df42a5068b4c6bdade94 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 22 Nov 2017 16:47:56 -0800 Subject: [PATCH 6/9] GUACAMOLE-96: Map base JDBC support for arbitrary attributes to PostgreSQL tables. --- .../schema/001-create-schema.sql | 96 +++++++++++++++ .../schema/upgrade/upgrade-pre-0.9.15.sql | 114 ++++++++++++++++++ .../auth/jdbc/connection/ConnectionMapper.xml | 58 ++++++++- .../connectiongroup/ConnectionGroupMapper.xml | 58 ++++++++- .../sharingprofile/SharingProfileMapper.xml | 67 +++++++++- .../guacamole/auth/jdbc/user/UserMapper.xml | 82 ++++++++++++- 6 files changed, 461 insertions(+), 14 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-0.9.15.sql diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql index 97780a541..ddd3566c2 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql @@ -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. diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-0.9.15.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-0.9.15.sql new file mode 100644 index 000000000..db115c230 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-0.9.15.sql @@ -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); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml index dc8fdd495..0b109f6ba 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml @@ -47,6 +47,14 @@ + + + + + + @@ -87,7 +95,7 @@ @@ -242,4 +275,25 @@ WHERE connection_id = #{object.objectID,jdbcType=INTEGER}::integer + + + DELETE FROM guacamole_connection_attribute + WHERE connection_id = #{object.objectID,jdbcType=INTEGER} + + + + + INSERT INTO guacamole_connection_attribute ( + connection_id, + attribute_name, + attribute_value + ) + VALUES + + (#{object.objectID,jdbcType=INTEGER}, + #{attribute.name,jdbcType=VARCHAR}, + #{attribute.value,jdbcType=VARCHAR}) + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml index 0a41b3d6b..7cc4ac7fa 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml @@ -48,6 +48,14 @@ + + + + + + @@ -88,7 +96,7 @@ @@ -229,4 +262,25 @@ WHERE connection_group_id = #{object.objectID,jdbcType=INTEGER}::integer + + + DELETE FROM guacamole_connection_group_attribute + WHERE connection_group_id = #{object.objectID,jdbcType=INTEGER} + + + + + INSERT INTO guacamole_connection_group_attribute ( + connection_group_id, + attribute_name, + attribute_value + ) + VALUES + + (#{object.objectID,jdbcType=INTEGER}, + #{attribute.name,jdbcType=VARCHAR}, + #{attribute.value,jdbcType=VARCHAR}) + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml index 0af493751..801d6e363 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml @@ -25,9 +25,20 @@ + + + + + + + + + @@ -46,7 +57,8 @@ - SELECT sharing_profile_id, @@ -57,12 +69,24 @@ #{identifier,jdbcType=INTEGER}::integer - + ; + + SELECT + sharing_profile_id, + attribute_name, + attribute_value + FROM guacamole_sharing_profile_attribute + WHERE sharing_profile_id IN + + #{identifier,jdbcType=INTEGER}::integer + ; - SELECT guacamole_sharing_profile.sharing_profile_id, @@ -76,7 +100,21 @@ #{identifier,jdbcType=INTEGER}::integer 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 + + #{identifier,jdbcType=INTEGER}::integer + + AND user_id = #{user.objectID,jdbcType=INTEGER} + AND permission = 'READ'; @@ -123,4 +161,25 @@ WHERE sharing_profile_id = #{object.objectID,jdbcType=INTEGER}::integer + + + DELETE FROM guacamole_sharing_profile_attribute + WHERE sharing_profile_id = #{object.objectID,jdbcType=INTEGER} + + + + + INSERT INTO guacamole_sharing_profile_attribute ( + sharing_profile_id, + attribute_name, + attribute_value + ) + VALUES + + (#{object.objectID,jdbcType=INTEGER}, + #{attribute.name,jdbcType=VARCHAR}, + #{attribute.value,jdbcType=VARCHAR}) + + + \ No newline at end of file diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml index c106a8fab..e183fe295 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml @@ -25,6 +25,8 @@ + + @@ -42,6 +44,15 @@ + + + + + + + @@ -61,7 +72,8 @@ - SELECT guacamole_user.user_id, @@ -88,12 +100,25 @@ open="(" separator="," close=")"> #{identifier,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 IN + + #{identifier,jdbcType=VARCHAR} + ; - SELECT guacamole_user.user_id, @@ -123,12 +148,28 @@ 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 + + #{identifier,jdbcType=VARCHAR} + + AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} + AND permission = 'READ'; - 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}; @@ -223,4 +272,25 @@ WHERE user_id = #{object.objectID,jdbcType=VARCHAR} + + + DELETE FROM guacamole_user_attribute + WHERE user_id = #{object.objectID,jdbcType=INTEGER} + + + + + INSERT INTO guacamole_user_attribute ( + user_id, + attribute_name, + attribute_value + ) + VALUES + + (#{object.objectID,jdbcType=INTEGER}, + #{attribute.name,jdbcType=VARCHAR}, + #{attribute.value,jdbcType=VARCHAR}) + + + From 6a834a1066ad65c63d64a4aa13c64ffba6acb9b0 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 25 Nov 2017 11:41:54 -0800 Subject: [PATCH 7/9] GUACAMOLE-96: Map base JDBC support for arbitrary attributes to MySQL tables. --- .../schema/001-create-schema.sql | 88 +++++++++++++++ .../schema/upgrade/upgrade-pre-0.9.15.sql | 106 ++++++++++++++++++ .../auth/jdbc/connection/ConnectionMapper.xml | 58 +++++++++- .../connectiongroup/ConnectionGroupMapper.xml | 58 +++++++++- .../sharingprofile/SharingProfileMapper.xml | 67 ++++++++++- .../guacamole/auth/jdbc/user/UserMapper.xml | 84 ++++++++++++-- 6 files changed, 446 insertions(+), 15 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-0.9.15.sql diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql index f26d2cc61..76711f118 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql @@ -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. diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-0.9.15.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-0.9.15.sql new file mode 100644 index 000000000..2979f533e --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-0.9.15.sql @@ -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; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml index cbffdd49b..e5fd2f03f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml @@ -47,6 +47,14 @@ + + + + + + @@ -87,7 +95,7 @@ @@ -242,4 +275,25 @@ WHERE connection_id = #{object.objectID,jdbcType=INTEGER} + + + DELETE FROM guacamole_connection_attribute + WHERE connection_id = #{object.objectID,jdbcType=INTEGER} + + + + + INSERT INTO guacamole_connection_attribute ( + connection_id, + attribute_name, + attribute_value + ) + VALUES + + (#{object.objectID,jdbcType=INTEGER}, + #{attribute.name,jdbcType=VARCHAR}, + #{attribute.value,jdbcType=VARCHAR}) + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml index f2ef3c297..e02a04640 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml @@ -48,6 +48,14 @@ + + + + + + @@ -88,7 +96,7 @@ @@ -229,4 +262,25 @@ WHERE connection_group_id = #{object.objectID,jdbcType=INTEGER} + + + DELETE FROM guacamole_connection_group_attribute + WHERE connection_group_id = #{object.objectID,jdbcType=INTEGER} + + + + + INSERT INTO guacamole_connection_group_attribute ( + connection_group_id, + attribute_name, + attribute_value + ) + VALUES + + (#{object.objectID,jdbcType=INTEGER}, + #{attribute.name,jdbcType=VARCHAR}, + #{attribute.value,jdbcType=VARCHAR}) + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml index 49bb337e1..ef899132f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml @@ -25,9 +25,20 @@ + + + + + + + + + @@ -46,7 +57,8 @@ - SELECT sharing_profile_id, @@ -57,12 +69,24 @@ #{identifier,jdbcType=VARCHAR} - + ; + + SELECT + sharing_profile_id, + attribute_name, + attribute_value + FROM guacamole_sharing_profile_attribute + WHERE sharing_profile_id IN + + #{identifier,jdbcType=VARCHAR} + ; - SELECT guacamole_sharing_profile.sharing_profile_id, @@ -76,7 +100,21 @@ #{identifier,jdbcType=VARCHAR} 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 + + #{identifier,jdbcType=VARCHAR} + + AND user_id = #{user.objectID,jdbcType=INTEGER} + AND permission = 'READ'; @@ -123,4 +161,25 @@ WHERE sharing_profile_id = #{object.objectID,jdbcType=INTEGER} + + + DELETE FROM guacamole_sharing_profile_attribute + WHERE sharing_profile_id = #{object.objectID,jdbcType=INTEGER} + + + + + INSERT INTO guacamole_sharing_profile_attribute ( + sharing_profile_id, + attribute_name, + attribute_value + ) + VALUES + + (#{object.objectID,jdbcType=INTEGER}, + #{attribute.name,jdbcType=VARCHAR}, + #{attribute.value,jdbcType=VARCHAR}) + + + \ No newline at end of file diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml index c9e4f70db..e183fe295 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml @@ -25,6 +25,8 @@ + + @@ -42,6 +44,15 @@ + + + + + + + @@ -61,7 +72,8 @@ - SELECT guacamole_user.user_id, @@ -88,12 +100,25 @@ open="(" separator="," close=")"> #{identifier,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 IN + + #{identifier,jdbcType=VARCHAR} + ; - SELECT guacamole_user.user_id, @@ -123,12 +148,28 @@ 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 + + #{identifier,jdbcType=VARCHAR} + + AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} + AND permission = 'READ'; - 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}; @@ -223,4 +272,25 @@ WHERE user_id = #{object.objectID,jdbcType=VARCHAR} - \ No newline at end of file + + + DELETE FROM guacamole_user_attribute + WHERE user_id = #{object.objectID,jdbcType=INTEGER} + + + + + INSERT INTO guacamole_user_attribute ( + user_id, + attribute_name, + attribute_value + ) + VALUES + + (#{object.objectID,jdbcType=INTEGER}, + #{attribute.name,jdbcType=VARCHAR}, + #{attribute.value,jdbcType=VARCHAR}) + + + + From 2d685766c01212f80602e5f00d85a6b8ed8a8ae2 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 25 Nov 2017 12:29:39 -0800 Subject: [PATCH 8/9] GUACAMOLE-96: Map base JDBC support for arbitrary attributes to SQL Server tables. --- .../schema/001-create-schema.sql | 110 +++++++++++++++ .../schema/upgrade/upgrade-pre-0.9.15.sql | 127 ++++++++++++++++++ .../auth/jdbc/connection/ConnectionMapper.xml | 58 +++++++- .../connectiongroup/ConnectionGroupMapper.xml | 58 +++++++- .../sharingprofile/SharingProfileMapper.xml | 69 +++++++++- .../guacamole/auth/jdbc/user/UserMapper.xml | 80 ++++++++++- 6 files changed, 488 insertions(+), 14 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-0.9.15.sql diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql index 060503a24..ee10ddaec 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/001-create-schema.sql @@ -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 + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-0.9.15.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-0.9.15.sql new file mode 100644 index 000000000..cb02dd5fa --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-0.9.15.sql @@ -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 diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml index 19c391224..fb617578b 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connection/ConnectionMapper.xml @@ -47,6 +47,14 @@ + + + + + + @@ -87,7 +95,7 @@ @@ -248,4 +281,25 @@ WHERE connection_id = #{object.objectID,jdbcType=INTEGER} + + + DELETE FROM [guacamole_connection_attribute] + WHERE connection_id = #{object.objectID,jdbcType=INTEGER} + + + + + INSERT INTO [guacamole_connection_attribute] ( + connection_id, + attribute_name, + attribute_value + ) + VALUES + + (#{object.objectID,jdbcType=INTEGER}, + #{attribute.name,jdbcType=VARCHAR}, + #{attribute.value,jdbcType=VARCHAR}) + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml index 452c0a81e..f75943ee4 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml @@ -48,6 +48,14 @@ + + + + + + @@ -88,7 +96,7 @@ @@ -229,4 +262,25 @@ WHERE connection_group_id = #{object.objectID,jdbcType=INTEGER} + + + DELETE FROM [guacamole_connection_group_attribute] + WHERE connection_group_id = #{object.objectID,jdbcType=INTEGER} + + + + + INSERT INTO [guacamole_connection_group_attribute] ( + connection_group_id, + attribute_name, + attribute_value + ) + VALUES + + (#{object.objectID,jdbcType=INTEGER}, + #{attribute.name,jdbcType=VARCHAR}, + #{attribute.value,jdbcType=VARCHAR}) + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml index 3b4ba0980..0b3212f53 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/sharingprofile/SharingProfileMapper.xml @@ -25,9 +25,20 @@ + + + + + + + + + @@ -46,7 +57,8 @@ - SELECT sharing_profile_id, @@ -57,12 +69,24 @@ #{identifier,jdbcType=INTEGER} - + ; + + SELECT + sharing_profile_id, + attribute_name, + attribute_value + FROM [guacamole_sharing_profile_attribute] + WHERE sharing_profile_id IN + + #{identifier,jdbcType=INTEGER} + ; - SELECT [guacamole_sharing_profile].sharing_profile_id, @@ -76,7 +100,21 @@ #{identifier,jdbcType=INTEGER} 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 + + #{identifier,jdbcType=INTEGER} + + AND user_id = #{user.objectID,jdbcType=INTEGER} + AND permission = 'READ'; @@ -123,4 +161,25 @@ WHERE sharing_profile_id = #{object.objectID,jdbcType=INTEGER} - + + + DELETE FROM [guacamole_sharing_profile_attribute] + WHERE sharing_profile_id = #{object.objectID,jdbcType=INTEGER} + + + + + INSERT INTO [guacamole_sharing_profile_attribute] ( + sharing_profile_id, + attribute_name, + attribute_value + ) + VALUES + + (#{object.objectID,jdbcType=INTEGER}, + #{attribute.name,jdbcType=VARCHAR}, + #{attribute.value,jdbcType=VARCHAR}) + + + + \ No newline at end of file diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml index 24db0132b..e9c5b0214 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/src/main/resources/org/apache/guacamole/auth/jdbc/user/UserMapper.xml @@ -25,6 +25,8 @@ + + @@ -42,6 +44,15 @@ + + + + + + + @@ -61,7 +72,8 @@ - SELECT [guacamole_user].user_id, @@ -92,10 +104,23 @@ #{identifier,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 IN + + #{identifier,jdbcType=INTEGER} + ; + - SELECT [guacamole_user].user_id, @@ -127,12 +152,28 @@ #{identifier,jdbcType=VARCHAR} 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 + + #{identifier,jdbcType=INTEGER} + + AND [guacamole_user_permission].user_id = #{user.objectID,jdbcType=INTEGER} + AND permission = 'READ'; - 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}; @@ -230,4 +279,25 @@ WHERE user_id = #{object.objectID,jdbcType=VARCHAR} + + + DELETE FROM [guacamole_user_attribute] + WHERE user_id = #{object.objectID,jdbcType=INTEGER} + + + + + INSERT INTO [guacamole_user_attribute] ( + user_id, + attribute_name, + attribute_value + ) + VALUES + + (#{object.objectID,jdbcType=INTEGER}, + #{attribute.name,jdbcType=VARCHAR}, + #{attribute.value,jdbcType=VARCHAR}) + + + From d5768ead6dc1044d3ee86b1dc05c280aaee80b01 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 30 Jan 2018 13:24:32 -0800 Subject: [PATCH 9/9] GUACAMOLE-96: Correct version number of upgrade scripts for next release (it will be 1.0.0, not 0.9.15). --- .../upgrade/{upgrade-pre-0.9.15.sql => upgrade-pre-1.0.0.sql} | 0 .../upgrade/{upgrade-pre-0.9.15.sql => upgrade-pre-1.0.0.sql} | 0 .../upgrade/{upgrade-pre-0.9.15.sql => upgrade-pre-1.0.0.sql} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/{upgrade-pre-0.9.15.sql => upgrade-pre-1.0.0.sql} (100%) rename extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/{upgrade-pre-0.9.15.sql => upgrade-pre-1.0.0.sql} (100%) rename extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/{upgrade-pre-0.9.15.sql => upgrade-pre-1.0.0.sql} (100%) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-0.9.15.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.0.0.sql similarity index 100% rename from extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-0.9.15.sql rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/upgrade/upgrade-pre-1.0.0.sql diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-0.9.15.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.0.0.sql similarity index 100% rename from extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-0.9.15.sql rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/upgrade/upgrade-pre-1.0.0.sql diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-0.9.15.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.0.0.sql similarity index 100% rename from extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-0.9.15.sql rename to extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-sqlserver/schema/upgrade/upgrade-pre-1.0.0.sql