You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by vn...@apache.org on 2018/02/01 18:32:49 UTC

[06/10] guacamole-client git commit: GUACAMOLE-96: Add base support within JDBC auth for storage of arbitrary attributes from other extensions.

GUACAMOLE-96: Add base support within JDBC auth for storage of arbitrary attributes from other extensions.


Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/b6de402c
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/b6de402c
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/b6de402c

Branch: refs/heads/master
Commit: b6de402c0c1fbcaa2d6e95ebbc99baef9165bbe9
Parents: a3cee15
Author: Michael Jumper <mj...@apache.org>
Authored: Wed Nov 22 12:29:58 2017 -0800
Committer: Michael Jumper <mj...@apache.org>
Committed: Wed Jan 31 15:26:16 2018 -0800

----------------------------------------------------------------------
 .../auth/jdbc/base/ArbitraryAttributeMap.java   | 162 +++++++++++++++++++
 .../auth/jdbc/base/ArbitraryAttributeModel.java | 104 ++++++++++++
 .../auth/jdbc/base/ModeledDirectoryObject.java  |  33 ++--
 .../jdbc/base/ModeledDirectoryObjectMapper.java |  25 ++-
 .../base/ModeledDirectoryObjectService.java     |  12 ++
 .../guacamole/auth/jdbc/base/ObjectModel.java   |  49 ++++--
 6 files changed, 354 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/b6de402c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ArbitraryAttributeMap.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 0000000..e2cb438
--- /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<String, String> {
+
+    /**
+     * Creates a new ArbitraryAttributeMap containing the name/value pairs
+     * within the given collection of model objects.
+     *
+     * @param models
+     *     The model objects of all attributes which should be stored in the
+     *     new map as name/value pairs.
+     *
+     * @return
+     *     A new ArbitraryAttributeMap containing the name/value pairs within
+     *     the given collection of model objects.
+     */
+    public static ArbitraryAttributeMap fromModelCollection(Collection<ArbitraryAttributeModel> models) {
+
+        // Add all name/value pairs from the given collection to the map
+        ArbitraryAttributeMap map = new ArbitraryAttributeMap();
+        for (ArbitraryAttributeModel model : models)
+            map.put(model.getName(), model.getValue());
+
+        return map;
+
+    }
+
+    /**
+     * Returns a collection of model objects which mirrors the contents of this
+     * ArbitraryAttributeMap. Each name/value pair within the map is reflected
+     * by a corresponding model object within the returned collection. Removing
+     * a model object from the collection removes the corresponding name/value
+     * pair from the map. Adding a new model object to the collection adds a
+     * corresponding name/value pair to the map. Changes to a model object
+     * within the collection are NOT reflected on the map, however.
+     *
+     * @return
+     *     A collection of model objects which mirrors the contents of this
+     *     ArbitraryAttributeMap.
+     */
+    public Collection<ArbitraryAttributeModel> toModelCollection() {
+        return new AbstractCollection<ArbitraryAttributeModel>() {
+
+            @Override
+            public void clear() {
+                ArbitraryAttributeMap.this.clear();
+            }
+
+            @Override
+            public boolean remove(Object o) {
+
+                // The Collection view of an ArbitraryAttributeMap can contain
+                // only ArbitraryAttributeModel objects
+                if (!(o instanceof ArbitraryAttributeModel))
+                    return false;
+
+                // The attribute should be removed only if the value matches
+                ArbitraryAttributeModel model = (ArbitraryAttributeModel) o;
+                return ArbitraryAttributeMap.this.remove(model.getName(),
+                        model.getValue());
+
+            }
+
+            @Override
+            public boolean add(ArbitraryAttributeModel e) {
+
+                String newValue = e.getValue();
+                String oldValue = put(e.getName(), newValue);
+
+                // If null value is being added, collection changed only if
+                // old value was non-null
+                if (newValue == null)
+                    return oldValue != null;
+
+                // Collection changed if value changed
+                return !newValue.equals(oldValue);
+
+            }
+
+            @Override
+            public boolean contains(Object o) {
+
+                // The Collection view of an ArbitraryAttributeMap can contain
+                // only ArbitraryAttributeModel objects
+                if (!(o instanceof ArbitraryAttributeModel))
+                    return false;
+
+                // No need to check the value of the attribute if the attribute
+                // is not even present
+                ArbitraryAttributeModel model = (ArbitraryAttributeModel) o;
+                String value = get(model.getName());
+                if (value == null)
+                    return false;
+
+                // The name/value pair is present only if the value matches
+                return value.equals(model.getValue());
+
+            }
+
+            @Override
+            public Iterator<ArbitraryAttributeModel> iterator() {
+
+                // Get iterator over all string name/value entries
+                final Iterator<Entry<String, String>> iterator = entrySet().iterator();
+
+                // Dynamically translate each string name/value entry into a
+                // corresponding attribute model object as iteration continues
+                return new Iterator<ArbitraryAttributeModel>() {
+
+                    @Override
+                    public boolean hasNext() {
+                        return iterator.hasNext();
+                    }
+
+                    @Override
+                    public ArbitraryAttributeModel next() {
+                        Entry<String, String> entry = iterator.next();
+                        return new ArbitraryAttributeModel(entry.getKey(),
+                                entry.getValue());
+                    }
+
+                };
+
+            }
+
+            @Override
+            public int size() {
+                return ArbitraryAttributeMap.this.size();
+            }
+
+        };
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/b6de402c/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/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 0000000..b064b54
--- /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;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/b6de402c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObject.java
----------------------------------------------------------------------
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 e13445b..ddeda92 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<ModelType extends ObjectModel>
 
     @Override
     public Map<String, String> getAttributes() {
-
-        // If no arbitrary attributes are defined, just return an empty map
-        Map<String, String> arbitraryAttributes = getModel().getArbitraryAttributes();
-        if (arbitraryAttributes == null)
-            return new HashMap<String, String>();
-
-        // Otherwise include any defined arbitrary attributes
-        return new HashMap<String, String>(arbitraryAttributes);
-
+        return new HashMap<String, String>(getModel().getArbitraryAttributeMap());
     }
 
     @Override
     public void setAttributes(Map<String, String> attributes) {
 
+        ArbitraryAttributeMap arbitraryAttributes = getModel().getArbitraryAttributeMap();
+
         // Get set of all supported attribute names
         Set<String> supportedAttributes = getSupportedAttributeNames();
 
-        // Initialize model with empty map if no such map is already present
-        Map<String, String> arbitraryAttributes = getModel().getArbitraryAttributes();
-        if (arbitraryAttributes == null) {
-            arbitraryAttributes = new HashMap<String, String>();
-            getModel().setArbitraryAttributes(arbitraryAttributes);
-        }
-
         // Store remaining attributes only if not directly mapped to model
         for (Map.Entry<String, String> attribute : attributes.entrySet()) {
+
             String name = attribute.getKey();
-            if (!supportedAttributes.contains(name))
-                arbitraryAttributes.put(name, attribute.getValue());
+            String value = attribute.getValue();
+
+            // Handle null attributes as explicit removal of that attribute,
+            // as the underlying model cannot store null attribute values
+            if (!supportedAttributes.contains(name)) {
+                if (value == null)
+                    arbitraryAttributes.remove(name);
+                else
+                    arbitraryAttributes.put(name, value);
+            }
+
         }
 
     }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/b6de402c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectMapper.java
----------------------------------------------------------------------
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 ebd95d9..4431e8f 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<ModelType> {
      *     The number of rows updated.
      */
     int update(@Param("object") ModelType object);
-    
+
+    /**
+     * Deletes any arbitrary attributes currently associated with the given
+     * object in the database.
+     *
+     * @param object
+     *     The object whose arbitrary attributes should be deleted.
+     *
+     * @return
+     *     The number of rows deleted.
+     */
+    int deleteAttributes(@Param("object") ModelType object);
+
+    /**
+     * Inserts all arbitrary attributes associated with the given object.
+     *
+     * @param object
+     *     The object whose arbitrary attributes should be inserted.
+     *
+     * @return
+     *     The number of rows inserted.
+     */
+    int insertAttributes(@Param("object") ModelType object);
+
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/b6de402c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledDirectoryObjectService.java
----------------------------------------------------------------------
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 2c1402e..21508c4 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<InternalType extends Modeled
     }
 
     @Override
+    @Transactional
     public InternalType createObject(ModeledAuthenticatedUser user, ExternalType object)
         throws GuacamoleException {
 
@@ -461,6 +463,10 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
         // Add implicit permissions
         getPermissionMapper().insert(getImplicitPermissions(user, model));
 
+        // Add any arbitrary attributes
+        if (model.hasArbitraryAttributes())
+            getObjectMapper().insertAttributes(model);
+
         return getObjectInstance(user, model);
 
     }
@@ -477,6 +483,7 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
     }
 
     @Override
+    @Transactional
     public void updateObject(ModeledAuthenticatedUser user, InternalType object)
         throws GuacamoleException {
 
@@ -486,6 +493,11 @@ public abstract class ModeledDirectoryObjectService<InternalType extends Modeled
         // Update object
         getObjectMapper().update(model);
 
+        // Replace any existing arbitrary attributes
+        getObjectMapper().deleteAttributes(model);
+        if (model.hasArbitraryAttributes())
+            getObjectMapper().insertAttributes(model);
+
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/b6de402c/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ObjectModel.java
----------------------------------------------------------------------
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 3841f6f..c3052b1 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,7 +19,7 @@
 
 package org.apache.guacamole.auth.jdbc.base;
 
-import java.util.Map;
+import java.util.Collection;
 
 /**
  * Object representation of a Guacamole object, such as a user or connection,
@@ -41,7 +41,8 @@ public abstract class ObjectModel {
      * Map of all arbitrary attributes associated with this object but not
      * directly mapped to a particular column.
      */
-    private Map<String, String> arbitraryAttributes;
+    private ArbitraryAttributeMap arbitraryAttributes =
+            new ArbitraryAttributeMap();
 
     /**
      * Creates a new, empty object.
@@ -102,23 +103,47 @@ public abstract class ObjectModel {
      *     with this model which do not otherwise have explicit mappings to
      *     properties.
      */
-    public Map<String, String> getArbitraryAttributes() {
+    public ArbitraryAttributeMap getArbitraryAttributeMap() {
         return arbitraryAttributes;
     }
 
     /**
-     * Sets all arbitrary attribute name/value pairs associated with this
-     * model. The provided map should contain only attributes which are not
-     * explicitly supported by the model, as any explicitly-supported
-     * attributes should instead be mapped to corresponding properties.
+     * Returns whether at least one arbitrary attribute name/value pair has
+     * been associated with this object.
+     *
+     * @return
+     *     true if this object has at least one arbitrary attribute set, false
+     *     otherwise.
+     */
+    public boolean hasArbitraryAttributes() {
+        return !arbitraryAttributes.isEmpty();
+    }
+
+    /**
+     * Returns a Collection view of the equivalent attribute model objects
+     * which make up the map of arbitrary attribute name/value pairs returned
+     * by getArbitraryAttributeMap(). Additions and removals on the returned
+     * Collection directly affect the attribute map.
+     *
+     * @return
+     *      A Collection view of the map returned by
+     *      getArbitraryAttributeMap().
+     */
+    public Collection<ArbitraryAttributeModel> getArbitraryAttributes() {
+        return arbitraryAttributes.toModelCollection();
+    }
+
+    /**
+     * Replaces all arbitrary attributes associated with this object with the
+     * attribute name/value pairs within the given collection of model objects.
      *
      * @param arbitraryAttributes
-     *     A map of attribute name/value pairs for all attributes associated
-     *     with this model which do not otherwise have explicit mappings to
-     *     properties.
+     *     The Collection of model objects containing the attribute name/value
+     *     pairs which should replace all currently-stored arbitrary attributes,
+     *     if any.
      */
-    public void setArbitraryAttributes(Map<String, String> arbitraryAttributes) {
-        this.arbitraryAttributes = arbitraryAttributes;
+    public void setArbitraryAttributes(Collection<ArbitraryAttributeModel> arbitraryAttributes) {
+        this.arbitraryAttributes = ArbitraryAttributeMap.fromModelCollection(arbitraryAttributes);
     }
 
 }