From ee40db759c09d68361a6d47894086013db546595 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 10 Feb 2015 15:50:00 -0800 Subject: [PATCH 01/19] GUAC-1100: Add getAll() to Directory. Create AbstractDirectory and migrate the Simple* implementations appropriately. --- .../guacamole/net/auth/Directory.java | 24 +++ .../simple/SimpleConnectionDirectory.java | 52 +----- .../SimpleConnectionGroupDirectory.java | 51 +----- .../net/auth/simple/SimpleDirectory.java | 153 ++++++++++++++++++ .../net/auth/simple/SimpleUserDirectory.java | 51 +----- 5 files changed, 195 insertions(+), 136 deletions(-) create mode 100644 guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleDirectory.java diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Directory.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Directory.java index e08446340..96f4f7b02 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Directory.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Directory.java @@ -22,6 +22,7 @@ package org.glyptodon.guacamole.net.auth; +import java.util.Collection; import java.util.Set; import org.glyptodon.guacamole.GuacamoleException; @@ -57,6 +58,29 @@ public interface Directory { */ ObjectType get(IdentifierType identifier) throws GuacamoleException; + /** + * Returns the objects having the given identifiers. Note that changes to + * any object returned will not necessarily affect the object stored within + * the Directory. To update an object stored within a + * Directory such that future calls to get() will return the updated + * object, you must call update() on the object after modification. + * + * @param identifiers + * The identifiers to use when locating the objects to return. + * + * @return + * The objects having the given identifiers. If any identifiers do not + * correspond to accessible objects, those identifiers will be ignored. + * If no objects correspond to any of the given identifiers, the + * returned collection will be empty. + * + * @throws GuacamoleException + * If an error occurs while retrieving the objects, or if permission + * to retrieve the requested objects is denied. + */ + Collection getAll(Collection identifiers) + throws GuacamoleException; + /** * Returns a Set containing all identifiers for all objects within this * Directory. diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionDirectory.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionDirectory.java index c5fe6594f..e7669b872 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionDirectory.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionDirectory.java @@ -25,11 +25,7 @@ package org.glyptodon.guacamole.net.auth.simple; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; -import org.glyptodon.guacamole.GuacamoleException; -import org.glyptodon.guacamole.GuacamoleSecurityException; import org.glyptodon.guacamole.net.auth.Connection; -import org.glyptodon.guacamole.net.auth.Directory; import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; /** @@ -39,13 +35,12 @@ import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; * * @author Michael Jumper */ -public class SimpleConnectionDirectory - implements Directory { +public class SimpleConnectionDirectory extends SimpleDirectory { /** * The Map of Connections to provide access to. */ - private Map connections = + private final Map connections = new HashMap(); /** @@ -60,56 +55,25 @@ public class SimpleConnectionDirectory // Create connections for each config for (Entry entry : configs.entrySet()) connections.put(entry.getKey(), - new SimpleConnection(entry.getKey(), entry.getKey(), + new SimpleConnection(entry.getKey(), entry.getKey(), entry.getValue())); + // Use the connection map to back the underlying AbstractDirectory + super.setObjects(connections); + } - @Override - public Connection get(String identifier) - throws GuacamoleException { - return connections.get(identifier); - } - - @Override - public Set getIdentifiers() throws GuacamoleException { - return connections.keySet(); - } - - @Override - public void add(Connection connection) - throws GuacamoleException { - throw new GuacamoleSecurityException("Permission denied."); - } - - @Override - public void update(Connection connection) - throws GuacamoleException { - throw new GuacamoleSecurityException("Permission denied."); - } - - @Override - public void remove(String identifier) throws GuacamoleException { - throw new GuacamoleSecurityException("Permission denied."); - } - - @Override - public void move(String identifier, Directory directory) - throws GuacamoleException { - throw new GuacamoleSecurityException("Permission denied."); - } - /** * An internal method for modifying the Connections in this Directory. * Returns the previous connection for the given identifier, if found. - * + * * @param connection The connection to add or update the Directory with. * @return The previous connection for the connection identifier, if found. */ public Connection putConnection(Connection connection) { return connections.put(connection.getIdentifier(), connection); } - + /** * An internal method for removing a Connection from this Directory. * @param identifier The identifier of the Connection to remove. diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroupDirectory.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroupDirectory.java index 0ebe52414..344cbcb4d 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroupDirectory.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroupDirectory.java @@ -25,11 +25,7 @@ package org.glyptodon.guacamole.net.auth.simple; import java.util.Collection; import java.util.HashMap; import java.util.Map; -import java.util.Set; -import org.glyptodon.guacamole.GuacamoleException; -import org.glyptodon.guacamole.GuacamoleSecurityException; import org.glyptodon.guacamole.net.auth.ConnectionGroup; -import org.glyptodon.guacamole.net.auth.Directory; /** * An extremely simple read-only implementation of a Directory of @@ -39,18 +35,18 @@ import org.glyptodon.guacamole.net.auth.Directory; * @author James Muehlner */ public class SimpleConnectionGroupDirectory - implements Directory { + extends SimpleDirectory { /** * The Map of ConnectionGroups to provide access to. */ - private Map connectionGroups = + private final Map connectionGroups = new HashMap(); /** * Creates a new SimpleConnectionGroupDirectory which contains the given * groups. - * + * * @param groups A Collection of all groups that should be present in this * connection group directory. */ @@ -60,46 +56,15 @@ public class SimpleConnectionGroupDirectory for (ConnectionGroup group : groups) connectionGroups.put(group.getIdentifier(), group); - } + // Use the connection group map to back the underlying AbstractDirectory + super.setObjects(connectionGroups); - @Override - public ConnectionGroup get(String identifier) - throws GuacamoleException { - return connectionGroups.get(identifier); - } - - @Override - public Set getIdentifiers() throws GuacamoleException { - return connectionGroups.keySet(); - } - - @Override - public void add(ConnectionGroup connectionGroup) - throws GuacamoleException { - throw new GuacamoleSecurityException("Permission denied."); - } - - @Override - public void update(ConnectionGroup connectionGroup) - throws GuacamoleException { - throw new GuacamoleSecurityException("Permission denied."); - } - - @Override - public void remove(String identifier) throws GuacamoleException { - throw new GuacamoleSecurityException("Permission denied."); - } - - @Override - public void move(String identifier, Directory directory) - throws GuacamoleException { - throw new GuacamoleSecurityException("Permission denied."); } /** * An internal method for modifying the ConnectionGroups in this Directory. * Returns the previous connection group for the given identifier, if found. - * + * * @param connectionGroup The connection group to add or update the * Directory with. * @return The previous connection group for the connection group @@ -108,10 +73,10 @@ public class SimpleConnectionGroupDirectory public ConnectionGroup putConnectionGroup(ConnectionGroup connectionGroup) { return connectionGroups.put(connectionGroup.getIdentifier(), connectionGroup); } - + /** * An internal method for removing a ConnectionGroup from this Directory. - * + * * @param identifier The identifier of the ConnectionGroup to remove. * @return The previous connection group for the given identifier, if found. */ diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleDirectory.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleDirectory.java new file mode 100644 index 000000000..d665a9687 --- /dev/null +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleDirectory.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.net.auth.simple; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.Set; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.GuacamoleSecurityException; +import org.glyptodon.guacamole.net.auth.Directory; + +/** + * An extremely simple read-only implementation of a Directory which provides + * access to a pre-defined Map of arbitrary objects. Any changes to the Map + * will affect the available contents of this SimpleDirectory. + * + * @author Michael Jumper + * @param + * The type of identifier used to identify objects stored within this + * SimpleDirectory. + * + * @param + * The type of objects stored within this SimpleDirectory. + */ +public class SimpleDirectory + implements Directory { + + /** + * The Map of objects to provide access to. + */ + private Map objects = Collections.EMPTY_MAP; + + /** + * Creates a new empty SimpleDirectory which does not provide access to + * any objects. + */ + public SimpleDirectory() { + } + + /** + * Creates a new SimpleDirectory which provides access to the objects + * contained within the given Map. + * + * @param objects + * The Map of objects to provide access to. + */ + public SimpleDirectory(Map objects) { + this.objects = objects; + } + + /** + * Sets the Map which backs this SimpleDirectory. Future function calls + * which retrieve objects from this SimpleDirectory will use the provided + * Map. + * + * @param objects + * The Map of objects to provide access to. + */ + protected void setObjects(Map objects) { + this.objects = objects; + } + + /** + * Returns the Map which currently backs this SimpleDirectory. Changes to + * this Map will affect future function calls that retrieve objects from + * this SimpleDirectory. + * + * @return + * The Map of objects which currently backs this SimpleDirectory. + */ + protected Map getObjects() { + return objects; + } + + @Override + public ObjectType get(IdentifierType identifier) + throws GuacamoleException { + return objects.get(identifier); + } + + @Override + public Collection getAll(Collection identifiers) + throws GuacamoleException { + + // Create collection which has an appropriate initial size + Collection foundObjects = new ArrayList(identifiers.size()); + + // Populate collection with matching objects + for (IdentifierType identifier : identifiers) { + + // Add the object which has the current identifier, if any + ObjectType object = objects.get(identifier); + if (object != null) + foundObjects.add(object); + + } + + return foundObjects; + + } + + @Override + public Set getIdentifiers() throws GuacamoleException { + return objects.keySet(); + } + + @Override + public void add(ObjectType connection) + throws GuacamoleException { + throw new GuacamoleSecurityException("Permission denied."); + } + + @Override + public void update(ObjectType connection) + throws GuacamoleException { + throw new GuacamoleSecurityException("Permission denied."); + } + + @Override + public void remove(IdentifierType identifier) throws GuacamoleException { + throw new GuacamoleSecurityException("Permission denied."); + } + + @Override + public void move(IdentifierType identifier, + Directory directory) + throws GuacamoleException { + throw new GuacamoleSecurityException("Permission denied."); + } + +} diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserDirectory.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserDirectory.java index 97e6eefb3..de7bd08e8 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserDirectory.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserDirectory.java @@ -23,10 +23,6 @@ package org.glyptodon.guacamole.net.auth.simple; import java.util.Collections; -import java.util.Set; -import org.glyptodon.guacamole.GuacamoleException; -import org.glyptodon.guacamole.GuacamoleSecurityException; -import org.glyptodon.guacamole.net.auth.Directory; import org.glyptodon.guacamole.net.auth.User; /** @@ -35,12 +31,7 @@ import org.glyptodon.guacamole.net.auth.User; * * @author Michael Jumper */ -public class SimpleUserDirectory implements Directory { - - /** - * The only user to be contained within this directory. - */ - private User user; +public class SimpleUserDirectory extends SimpleDirectory { /** * Creates a new SimpleUserDirectory which provides access to the single @@ -49,45 +40,7 @@ public class SimpleUserDirectory implements Directory { * @param user The user to provide access to. */ public SimpleUserDirectory(User user) { - this.user = user; - } - - @Override - public User get(String username) throws GuacamoleException { - - // If username matches, return the user - if (user.getUsername().equals(username)) - return user; - - // Otherwise, not found - return null; - - } - - @Override - public Set getIdentifiers() throws GuacamoleException { - return Collections.singleton(user.getUsername()); - } - - @Override - public void add(User user) throws GuacamoleException { - throw new GuacamoleSecurityException("Permission denied."); - } - - @Override - public void update(User user) throws GuacamoleException { - throw new GuacamoleSecurityException("Permission denied."); - } - - @Override - public void remove(String username) throws GuacamoleException { - throw new GuacamoleSecurityException("Permission denied."); - } - - @Override - public void move(String identifier, Directory directory) - throws GuacamoleException { - throw new GuacamoleSecurityException("Permission denied."); + super(Collections.singletonMap(user.getUsername(), user)); } } From df463a082af4c221ffdecb3523a33bfeebba8a1f Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 10 Feb 2015 17:44:59 -0800 Subject: [PATCH 02/19] GUAC-1100: Use permission sets for permission retrieval and manipulation. --- .../glyptodon/guacamole/net/auth/User.java | 43 +++--- .../auth/permission/ObjectPermissionSet.java | 128 ++++++++++++++++++ .../auth/permission/SystemPermissionSet.java | 77 +++++++++++ 3 files changed, 226 insertions(+), 22 deletions(-) create mode 100644 guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermissionSet.java create mode 100644 guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/SystemPermissionSet.java diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/User.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/User.java index 8409844c1..2cd5fea75 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/User.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/User.java @@ -22,9 +22,9 @@ package org.glyptodon.guacamole.net.auth; -import java.util.Set; import org.glyptodon.guacamole.GuacamoleException; -import org.glyptodon.guacamole.net.auth.permission.Permission; +import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet; +import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet; /** @@ -77,40 +77,39 @@ public interface User { * permissions, or if reading all permissions * is not allowed. */ - Set getPermissions() throws GuacamoleException; + SystemPermissionSet getSystemPermissions() throws GuacamoleException; /** - * Tests whether this user has the specified permission. + * Lists all permissions given to this user. * - * @param permission The permission to check. - * @return true if the permission is granted to this user, false otherwise. + * @return A Set of all permissions granted to this user. * - * @throws GuacamoleException If an error occurs while checking permissions, - * or if permissions cannot be checked due to - * lack of permissions to do so. + * @throws GuacamoleException If an error occurs while retrieving + * permissions, or if reading all permissions + * is not allowed. */ - boolean hasPermission(Permission permission) throws GuacamoleException; + ObjectPermissionSet getConnectionPermissions() throws GuacamoleException; /** - * Adds the specified permission to this user. + * Lists all permissions given to this user. * - * @param permission The permission to add. + * @return A Set of all permissions granted to this user. * - * @throws GuacamoleException If an error occurs while adding the - * permission. or if permission to add - * permissions is denied. + * @throws GuacamoleException If an error occurs while retrieving + * permissions, or if reading all permissions + * is not allowed. */ - void addPermission(Permission permission) throws GuacamoleException; + ObjectPermissionSet getConnectionGroupPermissions() throws GuacamoleException; /** - * Removes the specified permission from this specified user. + * Lists all permissions given to this user. * - * @param permission The permission to remove. + * @return A Set of all permissions granted to this user. * - * @throws GuacamoleException If an error occurs while removing the - * permission. or if permission to remove - * permissions is denied. + * @throws GuacamoleException If an error occurs while retrieving + * permissions, or if reading all permissions + * is not allowed. */ - void removePermission(Permission permission) throws GuacamoleException; + ObjectPermissionSet getUserPermissions() throws GuacamoleException; } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermissionSet.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermissionSet.java new file mode 100644 index 000000000..306417aac --- /dev/null +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermissionSet.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.net.auth.permission; + +import java.util.Collection; +import org.glyptodon.guacamole.GuacamoleException; + + +/** + * A set of permissions which affect arbitrary objects, where each object has + * an associated unique identifier. + * + * @author Michael Jumper + * @param + * The type of identifier used to identify objects affected by permissions + * stored in this ObjectPermissionSet. + * + * @param + * The type of objects affected by permissions stored in this + * ObjectPermissionSet. + */ +public interface ObjectPermissionSet { + + /** + * Tests whether the permission of the given type is granted for the + * object having the given identifier. + * + * @param permission + * The permission to check. + * + * @param identifier + * The identifier of the object affected by the permission being + * checked. + * + * @return + * true if the permission is granted, false otherwise. + * + * @throws GuacamoleException + * If an error occurs while checking permissions, or if permissions + * cannot be checked due to lack of permissions to do so. + */ + boolean hasPermission(ObjectPermission.Type permission, + IdentifierType identifier) throws GuacamoleException; + + /** + * Adds the specified permission for the object having the given + * identifier. + * + * @param permission + * The permission to add. + * + * @param identifier + * The identifier of the object affected by the permission being + * added. + * + * @throws GuacamoleException + * If an error occurs while adding the permission, or if permission to + * add permissions is denied. + */ + void addPermission(ObjectPermission.Type permission, + IdentifierType identifier) throws GuacamoleException; + + /** + * Removes the specified permission for the object having the given + * identifier. + * + * @param permission + * The permission to remove. + * + * @param identifier + * The identifier of the object affected by the permission being + * added. + * + * @throws GuacamoleException + * If an error occurs while removing the permission, or if permission + * to remove permissions is denied. + */ + void removePermission(ObjectPermission.Type permission, + IdentifierType identifier) throws GuacamoleException; + + /** + * Tests whether this user has the specified permissions for the objects + * having the given identifiers. The identifier of an object is returned + * in a new collection if at least one of the specified permissions is + * granted for that object. + * + * @param permissions + * The permissions to check. An identifier will be included in the + * resulting collection if at least one of these permissions is granted + * for the associated object + * + * @param identifiers + * The identifiers of the objects affected by the permissions being + * checked. + * + * @return + * A collection containing the subset of identifiers for which at least + * one of the specified permissions is granted. + * + * @throws GuacamoleException + * If an error occurs while checking permissions, or if permissions + * cannot be checked due to lack of permissions to do so. + */ + Collection getAccessibleObjects( + Collection permissions, + Collection identifiers) throws GuacamoleException; + +} diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/SystemPermissionSet.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/SystemPermissionSet.java new file mode 100644 index 000000000..e106cbc08 --- /dev/null +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/SystemPermissionSet.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.net.auth.permission; + +import org.glyptodon.guacamole.GuacamoleException; + + +/** + * A set of permissions which affects the system as a whole. + * + * @author Michael Jumper + */ +public interface SystemPermissionSet { + + /** + * Tests whether the permission of the given type is granted. + * + * @param permission + * The permission to check. + * + * @return + * true if the permission is granted, false otherwise. + * + * @throws GuacamoleException + * If an error occurs while checking permissions, or if permissions + * cannot be checked due to lack of permissions to do so. + */ + boolean hasPermission(SystemPermission.Type permission) + throws GuacamoleException; + + /** + * Adds the specified permission. + * + * @param permission + * The permission to add. + * + * @throws GuacamoleException + * If an error occurs while adding the permission, or if permission to + * add permissions is denied. + */ + void addPermission(SystemPermission.Type permission) + throws GuacamoleException; + + /** + * Removes the specified permission. + * + * @param permission + * The permission to remove. + * + * @throws GuacamoleException + * If an error occurs while removing the permission, or if permission + * to remove permissions is denied. + */ + void removePermission(SystemPermission.Type permission) + throws GuacamoleException; + +} From ed4ad2a431cd7c40c6f63d1107af6a350a10e462 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 11 Feb 2015 11:34:59 -0800 Subject: [PATCH 03/19] GUAC-1100: Make ObjectPermission concrete. Remove type-specific implementations. --- .../permission/ConnectionGroupPermission.java | 106 ------------------ .../auth/permission/ConnectionPermission.java | 106 ------------------ .../net/auth/permission/ObjectPermission.java | 75 ++++++++++++- .../net/auth/permission/UserPermission.java | 101 ----------------- 4 files changed, 72 insertions(+), 316 deletions(-) delete mode 100644 guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ConnectionGroupPermission.java delete mode 100644 guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ConnectionPermission.java delete mode 100644 guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/UserPermission.java diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ConnectionGroupPermission.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ConnectionGroupPermission.java deleted file mode 100644 index f24e63b64..000000000 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ConnectionGroupPermission.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2013 Glyptodon LLC - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package org.glyptodon.guacamole.net.auth.permission; - - -/** - * A permission which controls operations that directly affect a specific - * ConnectionGroup. Note that this permission only refers to the - * ConnectionGroup by its identifier. The actual ConnectionGroup - * is not stored within. - * - * @author James Muehlner - */ -public class ConnectionGroupPermission - implements ObjectPermission { - - /** - * The identifier of the GuacamoleConfiguration associated with the - * operation affected by this permission. - */ - private String identifier; - - /** - * The type of operation affected by this permission. - */ - private ObjectPermission.Type type; - - /** - * Creates a new ConnectionGroupPermission having the given type - * and identifier. The identifier must be the unique identifier assigned - * to the ConnectionGroup by the AuthenticationProvider in use. - * - * @param type The type of operation affected by this permission. - * @param identifier The identifier of the ConnectionGroup associated - * with the operation affected by this permission. - */ - public ConnectionGroupPermission(ObjectPermission.Type type, String identifier) { - - this.identifier = identifier; - this.type = type; - - } - - @Override - public String getObjectIdentifier() { - return identifier; - } - - @Override - public ObjectPermission.Type getType() { - return type; - } - - @Override - public int hashCode() { - int hash = 5; - if (identifier != null) hash = 47 * hash + identifier.hashCode(); - if (type != null) hash = 47 * hash + type.hashCode(); - return hash; - } - - @Override - public boolean equals(Object obj) { - - // Not equal if null or wrong type - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - - final ConnectionGroupPermission other = - (ConnectionGroupPermission) obj; - - // Not equal if different type - if (this.type != other.type) - return false; - - // If null identifier, equality depends on whether other identifier - // is null - if (identifier == null) - return other.identifier == null; - - // Otherwise, equality depends entirely on identifier - return identifier.equals(other.identifier); - - } - -} diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ConnectionPermission.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ConnectionPermission.java deleted file mode 100644 index 0802af5af..000000000 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ConnectionPermission.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2013 Glyptodon LLC - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package org.glyptodon.guacamole.net.auth.permission; - - -/** - * A permission which controls operations that directly affect a specific - * GuacamoleConfiguration. Note that this permission only refers to the - * GuacamoleConfiguration by its identifier. The actual GuacamoleConfiguration - * is not stored within. - * - * @author Michael Jumper - */ -public class ConnectionPermission - implements ObjectPermission { - - /** - * The identifier of the GuacamoleConfiguration associated with the - * operation affected by this permission. - */ - private String identifier; - - /** - * The type of operation affected by this permission. - */ - private Type type; - - /** - * Creates a new ConnectionPermission having the given type - * and identifier. The identifier must be the unique identifier assigned - * to the GuacamoleConfiguration by the AuthenticationProvider in use. - * - * @param type The type of operation affected by this permission. - * @param identifier The identifier of the GuacamoleConfiguration associated - * with the operation affected by this permission. - */ - public ConnectionPermission(Type type, String identifier) { - - this.identifier = identifier; - this.type = type; - - } - - @Override - public String getObjectIdentifier() { - return identifier; - } - - @Override - public Type getType() { - return type; - } - - @Override - public int hashCode() { - int hash = 5; - if (identifier != null) hash = 47 * hash + identifier.hashCode(); - if (type != null) hash = 47 * hash + type.hashCode(); - return hash; - } - - @Override - public boolean equals(Object obj) { - - // Not equal if null or wrong type - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - - final ConnectionPermission other = - (ConnectionPermission) obj; - - // Not equal if different type - if (this.type != other.type) - return false; - - // If null identifier, equality depends on whether other identifier - // is null - if (identifier == null) - return other.identifier == null; - - // Otherwise, equality depends entirely on identifier - return identifier.equals(other.identifier); - - } - -} diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermission.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermission.java index f079ae4fc..c776e3414 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermission.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermission.java @@ -28,9 +28,10 @@ package org.glyptodon.guacamole.net.auth.permission; * whole. * * @author Michael Jumper - * @param The type of identifier used by the object this permission affects. + * @param + * The type of identifier used by the object this permission affects. */ -public interface ObjectPermission extends Permission { +public class ObjectPermission implements Permission { /** * Specific types of object-level permissions. Each permission type is @@ -61,12 +62,80 @@ public interface ObjectPermission extends Permission { } /** + * The identifier of the GuacamoleConfiguration associated with the + * operation affected by this permission. + */ + private final IdentifierType identifier; + + /** + * The type of operation affected by this permission. + */ + private final Type type; + + /** + * Creates a new ObjectPermission having the given type and identifier. + * The identifier must be the unique identifier assigned to the object + * associated with this permission by the AuthenticationProvider in use. + * + * @param type + * The type of operation affected by this permission. + * + * @param identifier + * The identifier of the object associated with the operation affected + * by this permission. + */ + public ObjectPermission(Type type, IdentifierType identifier) { + + this.identifier = identifier; + this.type = type; + + } + + /** * Returns the identifier of the specific object affected by this * permission. * * @return The identifier of the specific object affected by this * permission. */ - public T getObjectIdentifier(); + public IdentifierType getObjectIdentifier() { + return identifier; + } + + @Override + public Type getType() { + return type; + } + + @Override + public int hashCode() { + int hash = 5; + if (identifier != null) hash = 47 * hash + identifier.hashCode(); + if (type != null) hash = 47 * hash + type.hashCode(); + return hash; + } + + @Override + public boolean equals(Object obj) { + + // Not equal if null or wrong type + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + + final ObjectPermission other = (ObjectPermission) obj; + + // Not equal if different type + if (this.type != other.type) + return false; + + // If null identifier, equality depends on whether other identifier + // is null + if (identifier == null) + return other.identifier == null; + + // Otherwise, equality depends entirely on identifier + return identifier.equals(other.identifier); + + } } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/UserPermission.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/UserPermission.java deleted file mode 100644 index 89aa085b8..000000000 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/UserPermission.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2013 Glyptodon LLC - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -package org.glyptodon.guacamole.net.auth.permission; - - -/** - * A permission which controls operations that directly affect a specific - * User. - * - * @author Michael Jumper - */ -public class UserPermission implements ObjectPermission { - - /** - * The username of the User associated with the operation affected by this - * permission. - */ - private String identifier; - - /** - * The type of operation affected by this permission. - */ - private Type type; - - /** - * Creates a new UserPermission having the given type and identifier. The - * identifier must be the user's username. - * - * @param type The type of operation affected by this permission. - * @param identifier The username of the User associated with the operation - * affected by this permission. - */ - public UserPermission(Type type, String identifier) { - - this.identifier = identifier; - this.type = type; - - } - - @Override - public String getObjectIdentifier() { - return identifier; - } - - @Override - public Type getType() { - return type; - } - - @Override - public int hashCode() { - int hash = 5; - if (identifier != null) hash = 47 * hash + identifier.hashCode(); - if (type != null) hash = 47 * hash + type.hashCode(); - return hash; - } - - @Override - public boolean equals(Object obj) { - - // Not equal if null or wrong type - if (obj == null) return false; - if (getClass() != obj.getClass()) return false; - - final UserPermission other = (UserPermission) obj; - - // Not equal if different type - if (this.type != other.type) - return false; - - // If null identifier, equality depends on whether other identifier - // is null - if (identifier == null) - return other.identifier == null; - - // Otherwise, equality depends entirely on identifier - return identifier.equals(other.identifier); - - } - -} From 1d2e7035560ec4becccfb4b19370b7cb0d381498 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 11 Feb 2015 11:36:06 -0800 Subject: [PATCH 04/19] GUAC-1100: Implement Simple* read-only versions of the permission sets. --- .../simple/SimpleObjectPermissionSet.java | 147 ++++++++++++++++++ .../simple/SimpleSystemPermissionSet.java | 109 +++++++++++++ 2 files changed, 256 insertions(+) create mode 100644 guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleObjectPermissionSet.java create mode 100644 guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleSystemPermissionSet.java diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleObjectPermissionSet.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleObjectPermissionSet.java new file mode 100644 index 000000000..2a3b990af --- /dev/null +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleObjectPermissionSet.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.net.auth.simple; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.GuacamoleSecurityException; +import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; +import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet; + +/** + * A read-only implementation of ObjectPermissionSet which uses a backing Set + * of Permissions to determine which permissions are present. + * + * @author Michael Jumper + * @param + * The type of identifier used to identify objects affected by permissions + * stored in this SimpleObjectPermissionSet. + * + * @param + * The type of objects affected by permissions stored in this + * SimpleObjectPermissionSet. + */ +public class SimpleObjectPermissionSet + implements ObjectPermissionSet { + + /** + * The set of all permissions currently granted. + */ + private Set> permissions = Collections.EMPTY_SET; + + /** + * Creates a new empty SimpleObjectPermissionSet. + */ + public SimpleObjectPermissionSet() { + } + + /** + * Creates a new SimpleObjectPermissionSet which contains the permissions + * within the given Set. + * + * @param permissions + * The Set of permissions this SimpleObjectPermissionSet should + * contain. + */ + public SimpleObjectPermissionSet(Set> permissions) { + this.permissions = permissions; + } + + /** + * Sets the Set which backs this SimpleObjectPermissionSet. Future function + * calls on this SimpleObjectPermissionSet will use the provided Set. + * + * @param permissions + * The Set of permissions this SimpleObjectPermissionSet should + * contain. + */ + protected void setPermissions(Set> permissions) { + this.permissions = permissions; + } + + /** + * Returns the Set which currently backs this SimpleObjectPermissionSet. + * Changes to this Set will affect future function calls on this + * SimpleObjectPermissionSet. + * + * @return + * The Set of permissions this SimpleObjectPermissionSet currently + * contains. + */ + protected Set> getPermissions() { + return permissions; + } + + + @Override + public boolean hasPermission(ObjectPermission.Type permission, + IdentifierType identifier) throws GuacamoleException { + + ObjectPermission objectPermission = + new ObjectPermission(permission, identifier); + + return permissions.contains(objectPermission); + + } + + @Override + public void addPermission(ObjectPermission.Type permission, + IdentifierType identifier) throws GuacamoleException { + throw new GuacamoleSecurityException("Permission denied."); + } + + @Override + public void removePermission(ObjectPermission.Type permission, + IdentifierType identifier) throws GuacamoleException { + throw new GuacamoleSecurityException("Permission denied."); + } + + @Override + public Collection getAccessibleObjects( + Collection permissionTypes, + Collection identifiers) throws GuacamoleException { + + Collection accessibleObjects = new ArrayList(permissions.size()); + + // For each identifier/permission combination + for (IdentifierType identifier : identifiers) { + for (ObjectPermission.Type permissionType : permissionTypes) { + + // Add identifier if at least one requested permission is granted + ObjectPermission permission = new ObjectPermission(permissionType, identifier); + if (permissions.contains(permission)) { + accessibleObjects.add(identifier); + break; + } + + } + } + + return accessibleObjects; + + } + +} diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleSystemPermissionSet.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleSystemPermissionSet.java new file mode 100644 index 000000000..5b027e5a9 --- /dev/null +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleSystemPermissionSet.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.net.auth.simple; + +import java.util.Collections; +import java.util.Set; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.GuacamoleSecurityException; +import org.glyptodon.guacamole.net.auth.permission.SystemPermission; +import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet; + +/** + * A read-only implementation of SystemPermissionSet which uses a backing Set + * of Permissions to determine which permissions are present. + * + * @author Michael Jumper + */ +public class SimpleSystemPermissionSet implements SystemPermissionSet { + + /** + * The set of all permissions currently granted. + */ + private Set permissions = Collections.EMPTY_SET; + + /** + * Creates a new empty SimpleSystemPermissionSet. + */ + public SimpleSystemPermissionSet() { + } + + /** + * Creates a new SimpleSystemPermissionSet which contains the permissions + * within the given Set. + * + * @param permissions + * The Set of permissions this SimpleSystemPermissionSet should + * contain. + */ + public SimpleSystemPermissionSet(Set permissions) { + this.permissions = permissions; + } + + /** + * Sets the Set which backs this SimpleSystemPermissionSet. Future function + * calls on this SimpleSystemPermissionSet will use the provided Set. + * + * @param permissions + * The Set of permissions this SimpleSystemPermissionSet should + * contain. + */ + protected void setPermissions(Set permissions) { + this.permissions = permissions; + } + + /** + * Returns the Set which currently backs this SimpleSystemPermissionSet. + * Changes to this Set will affect future function calls on this + * SimpleSystemPermissionSet. + * + * @return + * The Set of permissions this SimpleSystemPermissionSet currently + * contains. + */ + protected Set getPermissions() { + return permissions; + } + + @Override + public boolean hasPermission(SystemPermission.Type permission) + throws GuacamoleException { + + SystemPermission systemPermission = new SystemPermission(permission); + return permissions.contains(systemPermission); + + } + + @Override + public void addPermission(SystemPermission.Type permission) + throws GuacamoleException { + throw new GuacamoleSecurityException("Permission denied."); + } + + @Override + public void removePermission(SystemPermission.Type permission) + throws GuacamoleException { + throw new GuacamoleSecurityException("Permission denied."); + } + +} From cf36e5841a5f0e2ef06dc24c69aa0f0b8642ad29 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 11 Feb 2015 12:19:32 -0800 Subject: [PATCH 05/19] GUAC-1100: Bring SimpleUser up-to-date with API changes. --- .../guacamole/net/auth/simple/SimpleUser.java | 47 ++++++++++++------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java index abe447249..bdb9759a9 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java @@ -27,13 +27,13 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; import org.glyptodon.guacamole.GuacamoleException; -import org.glyptodon.guacamole.GuacamoleSecurityException; import org.glyptodon.guacamole.net.auth.AbstractUser; +import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionGroup; -import org.glyptodon.guacamole.net.auth.permission.ConnectionGroupPermission; -import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission; +import org.glyptodon.guacamole.net.auth.User; import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; -import org.glyptodon.guacamole.net.auth.permission.Permission; +import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet; +import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet; import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; /** @@ -44,9 +44,16 @@ import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; public class SimpleUser extends AbstractUser { /** - * The set of all permissions available to this user. + * All connection permissions granted to this user. */ - private Set permissions = new HashSet(); + private final Set> connectionPermissions = + new HashSet>(); + + /** + * All connection group permissions granted to this user. + */ + private final Set> connectionGroupPermissions = + new HashSet>(); /** * Creates a completely uninitialized SimpleUser. @@ -72,13 +79,13 @@ public class SimpleUser extends AbstractUser { for (String identifier : configs.keySet()) { // Create permission - Permission permission = new ConnectionPermission( + ObjectPermission permission = new ObjectPermission( ObjectPermission.Type.READ, identifier ); // Add to set - permissions.add(permission); + connectionPermissions.add(permission); } @@ -86,36 +93,40 @@ public class SimpleUser extends AbstractUser { for (ConnectionGroup group : groups) { // Create permission - Permission permission = new ConnectionGroupPermission( + ObjectPermission permission = new ObjectPermission( ObjectPermission.Type.READ, group.getIdentifier() ); // Add to set - permissions.add(permission); + connectionGroupPermissions.add(permission); } } @Override - public Set getPermissions() throws GuacamoleException { - return permissions; + public SystemPermissionSet getSystemPermissions() + throws GuacamoleException { + return new SimpleSystemPermissionSet(); } @Override - public boolean hasPermission(Permission permission) throws GuacamoleException { - return permissions.contains(permission); + public ObjectPermissionSet getConnectionPermissions() + throws GuacamoleException { + return new SimpleObjectPermissionSet(connectionPermissions); } @Override - public void addPermission(Permission permission) throws GuacamoleException { - throw new GuacamoleSecurityException("Permission denied."); + public ObjectPermissionSet getConnectionGroupPermissions() + throws GuacamoleException { + return new SimpleObjectPermissionSet(connectionGroupPermissions); } @Override - public void removePermission(Permission permission) throws GuacamoleException { - throw new GuacamoleSecurityException("Permission denied."); + public ObjectPermissionSet getUserPermissions() + throws GuacamoleException { + return new SimpleObjectPermissionSet(); } } From a22299466b8c1591e81a8f0ced3b9ae3fffd6be7 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 11 Feb 2015 12:27:10 -0800 Subject: [PATCH 06/19] GUAC-1100: Fix comments in User. ObjectPermissionSet does not need ObjectType parameter. --- .../glyptodon/guacamole/net/auth/User.java | 55 +++++++++++-------- .../auth/permission/ObjectPermissionSet.java | 6 +- .../simple/SimpleObjectPermissionSet.java | 8 +-- .../guacamole/net/auth/simple/SimpleUser.java | 12 ++-- 4 files changed, 41 insertions(+), 40 deletions(-) diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/User.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/User.java index 2cd5fea75..da5c632e4 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/User.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/User.java @@ -69,47 +69,56 @@ public interface User { public void setPassword(String password); /** - * Lists all permissions given to this user. + * Returns all system-level permissions given to this user. * - * @return A Set of all permissions granted to this user. + * @return + * A SystemPermissionSet of all system-level permissions granted to + * this user. * - * @throws GuacamoleException If an error occurs while retrieving - * permissions, or if reading all permissions - * is not allowed. + * @throws GuacamoleException + * If an error occurs while retrieving permissions, or if reading all + * permissions is not allowed. */ SystemPermissionSet getSystemPermissions() throws GuacamoleException; /** - * Lists all permissions given to this user. + * Returns all connection permissions given to this user. * - * @return A Set of all permissions granted to this user. + * @return + * An ObjectPermissionSet of all connection permissions granted to this + * user. * - * @throws GuacamoleException If an error occurs while retrieving - * permissions, or if reading all permissions - * is not allowed. + * @throws GuacamoleException + * If an error occurs while retrieving permissions, or if reading all + * permissions is not allowed. */ - ObjectPermissionSet getConnectionPermissions() throws GuacamoleException; + ObjectPermissionSet getConnectionPermissions() + throws GuacamoleException; /** - * Lists all permissions given to this user. + * Returns all connection group permissions given to this user. * - * @return A Set of all permissions granted to this user. + * @return + * An ObjectPermissionSet of all connection group permissions granted + * to this user. * - * @throws GuacamoleException If an error occurs while retrieving - * permissions, or if reading all permissions - * is not allowed. + * @throws GuacamoleException + * If an error occurs while retrieving permissions, or if reading all + * permissions is not allowed. */ - ObjectPermissionSet getConnectionGroupPermissions() throws GuacamoleException; + ObjectPermissionSet getConnectionGroupPermissions() + throws GuacamoleException; /** - * Lists all permissions given to this user. + * Returns all user permissions given to this user. * - * @return A Set of all permissions granted to this user. + * @return + * An ObjectPermissionSet of all user permissions granted to this user. * - * @throws GuacamoleException If an error occurs while retrieving - * permissions, or if reading all permissions - * is not allowed. + * @throws GuacamoleException + * If an error occurs while retrieving permissions, or if reading all + * permissions is not allowed. */ - ObjectPermissionSet getUserPermissions() throws GuacamoleException; + ObjectPermissionSet getUserPermissions() throws GuacamoleException; } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermissionSet.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermissionSet.java index 306417aac..490c5697d 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermissionSet.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermissionSet.java @@ -34,12 +34,8 @@ import org.glyptodon.guacamole.GuacamoleException; * @param * The type of identifier used to identify objects affected by permissions * stored in this ObjectPermissionSet. - * - * @param - * The type of objects affected by permissions stored in this - * ObjectPermissionSet. */ -public interface ObjectPermissionSet { +public interface ObjectPermissionSet { /** * Tests whether the permission of the given type is granted for the diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleObjectPermissionSet.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleObjectPermissionSet.java index 2a3b990af..d0132780c 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleObjectPermissionSet.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleObjectPermissionSet.java @@ -39,13 +39,9 @@ import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet; * @param * The type of identifier used to identify objects affected by permissions * stored in this SimpleObjectPermissionSet. - * - * @param - * The type of objects affected by permissions stored in this - * SimpleObjectPermissionSet. */ -public class SimpleObjectPermissionSet - implements ObjectPermissionSet { +public class SimpleObjectPermissionSet + implements ObjectPermissionSet { /** * The set of all permissions currently granted. diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java index bdb9759a9..0e75527e5 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java @@ -112,21 +112,21 @@ public class SimpleUser extends AbstractUser { } @Override - public ObjectPermissionSet getConnectionPermissions() + public ObjectPermissionSet getConnectionPermissions() throws GuacamoleException { - return new SimpleObjectPermissionSet(connectionPermissions); + return new SimpleObjectPermissionSet(connectionPermissions); } @Override - public ObjectPermissionSet getConnectionGroupPermissions() + public ObjectPermissionSet getConnectionGroupPermissions() throws GuacamoleException { - return new SimpleObjectPermissionSet(connectionGroupPermissions); + return new SimpleObjectPermissionSet(connectionGroupPermissions); } @Override - public ObjectPermissionSet getUserPermissions() + public ObjectPermissionSet getUserPermissions() throws GuacamoleException { - return new SimpleObjectPermissionSet(); + return new SimpleObjectPermissionSet(); } } From 7c353007f6bcea9c1488475f421ac3c1bc21a71f Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 11 Feb 2015 15:04:48 -0800 Subject: [PATCH 07/19] GUAC-1100: Add batch add/remove to permission sets. --- .../auth/permission/ObjectPermissionSet.java | 45 ++++++++++++++++++ .../auth/permission/SystemPermissionSet.java | 46 +++++++++++++++++++ .../simple/SimpleObjectPermissionSet.java | 25 +++++----- .../simple/SimpleSystemPermissionSet.java | 24 ++++++---- 4 files changed, 119 insertions(+), 21 deletions(-) diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermissionSet.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermissionSet.java index 490c5697d..fd8af692a 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermissionSet.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermissionSet.java @@ -23,6 +23,7 @@ package org.glyptodon.guacamole.net.auth.permission; import java.util.Collection; +import java.util.Set; import org.glyptodon.guacamole.GuacamoleException; @@ -121,4 +122,48 @@ public interface ObjectPermissionSet { Collection permissions, Collection identifiers) throws GuacamoleException; + /** + * Returns a Set which contains all permissions granted within this + * permission set. + * + * @return + * A Set containing all permissions granted within this permission set. + * + * @throws GuacamoleException + * If an error occurs while retrieving permissions, or if permissions + * cannot be retrieved due to lack of permissions to do so. + */ + Set> getPermissions() + throws GuacamoleException; + + /** + * Adds the specified permissions, if not already granted. If a specified + * permission is already granted, no operation is performed regarding that + * permission. + * + * @param permissions + * The permissions to add. + * + * @throws GuacamoleException + * If an error occurs while adding the permissions, or if permission to + * add permissions is denied. + */ + void addPermissions(Set> permissions) + throws GuacamoleException; + + /** + * Removes each of the specified permissions, if granted. If a specified + * permission is not granted, no operation is performed regarding that + * permission. + * + * @param permissions + * The permissions to remove. + * + * @throws GuacamoleException + * If an error occurs while removing the permissions, or if permission + * to remove permissions is denied. + */ + void removePermissions(Set> permissions) + throws GuacamoleException; + } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/SystemPermissionSet.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/SystemPermissionSet.java index e106cbc08..8acefff8d 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/SystemPermissionSet.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/SystemPermissionSet.java @@ -22,6 +22,7 @@ package org.glyptodon.guacamole.net.auth.permission; +import java.util.Set; import org.glyptodon.guacamole.GuacamoleException; @@ -74,4 +75,49 @@ public interface SystemPermissionSet { void removePermission(SystemPermission.Type permission) throws GuacamoleException; + /** + * Returns a Set which contains all system-level permissions granted within + * this permission set. + * + * @return + * A Set containing all system-level permissions granted within this + * permission set. + * + * @throws GuacamoleException + * If an error occurs while retrieving permissions, or if permissions + * cannot be retrieved due to lack of permissions to do so. + */ + Set getPermissions() throws GuacamoleException; + + /** + * Adds the specified permissions, if not already granted. If a specified + * permission is already granted, no operation is performed regarding that + * permission. + * + * @param permissions + * The permissions to add. + * + * @throws GuacamoleException + * If an error occurs while adding the permissions, or if permission to + * add permissions is denied. + */ + void addPermissions(Set permissions) + throws GuacamoleException; + + /** + * Removes each of the specified permissions, if granted. If a specified + * permission is not granted, no operation is performed regarding that + * permission. + * + * @param permissions + * The permissions to remove. + * + * @throws GuacamoleException + * If an error occurs while removing the permissions, or if permission + * to remove permissions is denied. + */ + void removePermissions(Set permissions) + throws GuacamoleException; + + } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleObjectPermissionSet.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleObjectPermissionSet.java index d0132780c..96a98b46a 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleObjectPermissionSet.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleObjectPermissionSet.java @@ -78,20 +78,11 @@ public class SimpleObjectPermissionSet this.permissions = permissions; } - /** - * Returns the Set which currently backs this SimpleObjectPermissionSet. - * Changes to this Set will affect future function calls on this - * SimpleObjectPermissionSet. - * - * @return - * The Set of permissions this SimpleObjectPermissionSet currently - * contains. - */ - protected Set> getPermissions() { + @Override + public Set> getPermissions() { return permissions; } - @Override public boolean hasPermission(ObjectPermission.Type permission, IdentifierType identifier) throws GuacamoleException { @@ -140,4 +131,16 @@ public class SimpleObjectPermissionSet } + @Override + public void addPermissions(Set> permissions) + throws GuacamoleException { + throw new GuacamoleSecurityException("Permission denied."); + } + + @Override + public void removePermissions(Set> permissions) + throws GuacamoleException { + throw new GuacamoleSecurityException("Permission denied."); + } + } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleSystemPermissionSet.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleSystemPermissionSet.java index 5b027e5a9..bd6a5c2e0 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleSystemPermissionSet.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleSystemPermissionSet.java @@ -72,16 +72,8 @@ public class SimpleSystemPermissionSet implements SystemPermissionSet { this.permissions = permissions; } - /** - * Returns the Set which currently backs this SimpleSystemPermissionSet. - * Changes to this Set will affect future function calls on this - * SimpleSystemPermissionSet. - * - * @return - * The Set of permissions this SimpleSystemPermissionSet currently - * contains. - */ - protected Set getPermissions() { + @Override + public Set getPermissions() { return permissions; } @@ -106,4 +98,16 @@ public class SimpleSystemPermissionSet implements SystemPermissionSet { throw new GuacamoleSecurityException("Permission denied."); } + @Override + public void addPermissions(Set permissions) + throws GuacamoleException { + throw new GuacamoleSecurityException("Permission denied."); + } + + @Override + public void removePermissions(Set permissions) + throws GuacamoleException { + throw new GuacamoleSecurityException("Permission denied."); + } + } From 3f5d398f131eee69f48cf5303911fa3f753ad5b8 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 11 Feb 2015 15:37:24 -0800 Subject: [PATCH 08/19] GUAC-1100: Extract batch operations on permission sets into interface. --- .../auth/permission/ObjectPermissionSet.java | 41 ++-------- .../net/auth/permission/PermissionSet.java | 82 +++++++++++++++++++ .../auth/permission/SystemPermissionSet.java | 42 +--------- 3 files changed, 91 insertions(+), 74 deletions(-) create mode 100644 guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/PermissionSet.java diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermissionSet.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermissionSet.java index fd8af692a..e90a646e0 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermissionSet.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermissionSet.java @@ -36,7 +36,8 @@ import org.glyptodon.guacamole.GuacamoleException; * The type of identifier used to identify objects affected by permissions * stored in this ObjectPermissionSet. */ -public interface ObjectPermissionSet { +public interface ObjectPermissionSet + extends PermissionSet> { /** * Tests whether the permission of the given type is granted for the @@ -122,47 +123,15 @@ public interface ObjectPermissionSet { Collection permissions, Collection identifiers) throws GuacamoleException; - /** - * Returns a Set which contains all permissions granted within this - * permission set. - * - * @return - * A Set containing all permissions granted within this permission set. - * - * @throws GuacamoleException - * If an error occurs while retrieving permissions, or if permissions - * cannot be retrieved due to lack of permissions to do so. - */ + @Override Set> getPermissions() throws GuacamoleException; - /** - * Adds the specified permissions, if not already granted. If a specified - * permission is already granted, no operation is performed regarding that - * permission. - * - * @param permissions - * The permissions to add. - * - * @throws GuacamoleException - * If an error occurs while adding the permissions, or if permission to - * add permissions is denied. - */ + @Override void addPermissions(Set> permissions) throws GuacamoleException; - /** - * Removes each of the specified permissions, if granted. If a specified - * permission is not granted, no operation is performed regarding that - * permission. - * - * @param permissions - * The permissions to remove. - * - * @throws GuacamoleException - * If an error occurs while removing the permissions, or if permission - * to remove permissions is denied. - */ + @Override void removePermissions(Set> permissions) throws GuacamoleException; diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/PermissionSet.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/PermissionSet.java new file mode 100644 index 000000000..1bfa717f8 --- /dev/null +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/PermissionSet.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.net.auth.permission; + +import java.util.Set; +import org.glyptodon.guacamole.GuacamoleException; + + +/** + * An arbitrary set of permissions. + * + * @author Michael Jumper + * @param + * The type of permission stored within this PermissionSet. + */ +public interface PermissionSet { + + /** + * Returns a Set which contains all permissions granted within this + * permission set. + * + * @return + * A Set containing all permissions granted within this permission set. + * + * @throws GuacamoleException + * If an error occurs while retrieving permissions, or if permissions + * cannot be retrieved due to lack of permissions to do so. + */ + Set getPermissions() throws GuacamoleException; + + /** + * Adds the specified permissions, if not already granted. If a specified + * permission is already granted, no operation is performed regarding that + * permission. + * + * @param permissions + * The permissions to add. + * + * @throws GuacamoleException + * If an error occurs while adding the permissions, or if permission to + * add permissions is denied. + */ + void addPermissions(Set permissions) + throws GuacamoleException; + + /** + * Removes each of the specified permissions, if granted. If a specified + * permission is not granted, no operation is performed regarding that + * permission. + * + * @param permissions + * The permissions to remove. + * + * @throws GuacamoleException + * If an error occurs while removing the permissions, or if permission + * to remove permissions is denied. + */ + void removePermissions(Set permissions) + throws GuacamoleException; + + +} diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/SystemPermissionSet.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/SystemPermissionSet.java index 8acefff8d..195c46e47 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/SystemPermissionSet.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/SystemPermissionSet.java @@ -31,7 +31,7 @@ import org.glyptodon.guacamole.GuacamoleException; * * @author Michael Jumper */ -public interface SystemPermissionSet { +public interface SystemPermissionSet extends PermissionSet { /** * Tests whether the permission of the given type is granted. @@ -75,49 +75,15 @@ public interface SystemPermissionSet { void removePermission(SystemPermission.Type permission) throws GuacamoleException; - /** - * Returns a Set which contains all system-level permissions granted within - * this permission set. - * - * @return - * A Set containing all system-level permissions granted within this - * permission set. - * - * @throws GuacamoleException - * If an error occurs while retrieving permissions, or if permissions - * cannot be retrieved due to lack of permissions to do so. - */ + @Override Set getPermissions() throws GuacamoleException; - /** - * Adds the specified permissions, if not already granted. If a specified - * permission is already granted, no operation is performed regarding that - * permission. - * - * @param permissions - * The permissions to add. - * - * @throws GuacamoleException - * If an error occurs while adding the permissions, or if permission to - * add permissions is denied. - */ + @Override void addPermissions(Set permissions) throws GuacamoleException; - /** - * Removes each of the specified permissions, if granted. If a specified - * permission is not granted, no operation is performed regarding that - * permission. - * - * @param permissions - * The permissions to remove. - * - * @throws GuacamoleException - * If an error occurs while removing the permissions, or if permission - * to remove permissions is denied. - */ + @Override void removePermissions(Set permissions) throws GuacamoleException; - } From 9fe2eb6bbd535cd1111b4693440a565d8395fe8d Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 11 Feb 2015 16:14:38 -0800 Subject: [PATCH 09/19] GUAC-1100: Migrate REST services to new guacamole-ext API. This is partial and temporary - batch operations are not being used, and the MySQL auth has not been updated. --- .../connection/ConnectionRESTService.java | 18 +- .../ConnectionGroupRESTService.java | 23 ++- .../rest/permission/APIPermissionSet.java | 188 ++++++++---------- .../net/basic/rest/user/APIUserWrapper.java | 48 ++--- .../net/basic/rest/user/UserRESTService.java | 110 ++++++---- 5 files changed, 189 insertions(+), 198 deletions(-) diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionRESTService.java index 67fb66258..0ec05e3f0 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionRESTService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionRESTService.java @@ -45,10 +45,10 @@ import org.glyptodon.guacamole.net.auth.ConnectionRecord; import org.glyptodon.guacamole.net.auth.Directory; import org.glyptodon.guacamole.net.auth.User; import org.glyptodon.guacamole.net.auth.UserContext; -import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission; import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; -import org.glyptodon.guacamole.net.auth.permission.Permission; +import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet; import org.glyptodon.guacamole.net.auth.permission.SystemPermission; +import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet; import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure; import org.glyptodon.guacamole.net.basic.rest.ObjectRetrievalService; import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService; @@ -71,12 +71,6 @@ public class ConnectionRESTService { */ private static final Logger logger = LoggerFactory.getLogger(ConnectionRESTService.class); - /** - * System administration permission. - */ - private static final Permission SYSTEM_PERMISSION = - new SystemPermission(SystemPermission.Type.ADMINISTER); - /** * A service for authenticating users from auth tokens. */ @@ -143,9 +137,13 @@ public class ConnectionRESTService { UserContext userContext = authenticationService.getUserContext(authToken); User self = userContext.self(); + // Retrieve permission sets + SystemPermissionSet systemPermissions = self.getSystemPermissions(); + ObjectPermissionSet connectionPermissions = self.getConnectionPermissions(); + // Deny access if adminstrative or update permission is missing - if (!self.hasPermission(SYSTEM_PERMISSION) - && !self.hasPermission(new ConnectionPermission(ObjectPermission.Type.UPDATE, connectionID))) + if (!systemPermissions.hasPermission(SystemPermission.Type.ADMINISTER) + && !connectionPermissions.hasPermission(ObjectPermission.Type.UPDATE, connectionID)) throw new GuacamoleSecurityException("Permission to read connection parameters denied."); // Retrieve the requested connection diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java index 049a9d1bc..651ddbd85 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java @@ -45,10 +45,10 @@ import org.glyptodon.guacamole.net.auth.ConnectionGroup; import org.glyptodon.guacamole.net.auth.Directory; import org.glyptodon.guacamole.net.auth.User; import org.glyptodon.guacamole.net.auth.UserContext; -import org.glyptodon.guacamole.net.auth.permission.ConnectionGroupPermission; -import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission; import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; +import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet; import org.glyptodon.guacamole.net.auth.permission.SystemPermission; +import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet; import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure; import org.glyptodon.guacamole.net.basic.rest.ObjectRetrievalService; import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService; @@ -102,14 +102,14 @@ public class ConnectionGroupRESTService { */ private boolean hasConnectionPermission(User user, String identifier, List permissions) throws GuacamoleException { + + // Retrieve connection permissions + ObjectPermissionSet connectionPermissions = user.getConnectionPermissions(); // Determine whether user has at least one of the given permissions for (ObjectPermission.Type permission : permissions) { - - ConnectionPermission connectionPermission = new ConnectionPermission(permission, identifier); - if (user.hasPermission(connectionPermission)) + if (connectionPermissions.hasPermission(permission, identifier)) return true; - } // None of the given permissions were present @@ -137,13 +137,13 @@ public class ConnectionGroupRESTService { private boolean hasConnectionGroupPermission(User user, String identifier, List permissions) throws GuacamoleException { + // Retrieve connection group permissions + ObjectPermissionSet connectionGroupPermissions = user.getConnectionGroupPermissions(); + // Determine whether user has at least one of the given permissions for (ObjectPermission.Type permission : permissions) { - - ConnectionGroupPermission connectionGroupPermission = new ConnectionGroupPermission(permission, identifier); - if (user.hasPermission(connectionGroupPermission)) + if (connectionGroupPermissions.hasPermission(permission, identifier)) return true; - } // None of the given permissions were present @@ -185,7 +185,8 @@ public class ConnectionGroupRESTService { User self = userContext.self(); // An admin user has access to any connection or connection group - boolean isAdmin = self.hasPermission(new SystemPermission(SystemPermission.Type.ADMINISTER)); + SystemPermissionSet systemPermissions = self.getSystemPermissions(); + boolean isAdmin = systemPermissions.hasPermission(SystemPermission.Type.ADMINISTER); // Retrieve specified connection group ConnectionGroup connectionGroup; diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/permission/APIPermissionSet.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/permission/APIPermissionSet.java index 450cbc823..1d4a14774 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/permission/APIPermissionSet.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/permission/APIPermissionSet.java @@ -24,17 +24,14 @@ package org.glyptodon.guacamole.net.basic.rest.permission; import java.util.EnumSet; import java.util.HashMap; -import java.util.HashSet; import java.util.Map; import java.util.Set; import org.glyptodon.guacamole.GuacamoleException; -import org.glyptodon.guacamole.GuacamoleServerException; -import org.glyptodon.guacamole.net.auth.permission.ConnectionGroupPermission; -import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission; +import org.glyptodon.guacamole.net.auth.User; import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; -import org.glyptodon.guacamole.net.auth.permission.Permission; +import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet; import org.glyptodon.guacamole.net.auth.permission.SystemPermission; -import org.glyptodon.guacamole.net.auth.permission.UserPermission; +import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet; /** * The set of permissions which are granted to a specific user, organized by @@ -50,97 +47,26 @@ public class APIPermissionSet { /** * Map of connection ID to the set of granted permissions. */ - private Map> connectionPermissions = new HashMap>(); + private Map> connectionPermissions = + new HashMap>(); /** * Map of connection group ID to the set of granted permissions. */ - private Map> connectionGroupPermissions = new HashMap>(); + private Map> connectionGroupPermissions = + new HashMap>(); /** * Map of user ID to the set of granted permissions. */ - private Map> userPermissions = new HashMap>(); + private Map> userPermissions = + new HashMap>(); /** * Set of all granted system-level permissions. */ - private EnumSet systemPermissions = EnumSet.noneOf(SystemPermission.Type.class); - - /** - * Adds the given object permission to the given map of object identifier - * to permission set. - * - * @param permissions - * The map to add the given permission to. - * - * @param permission - * The permission to add. - */ - private void addPermission(Map> permissions, ObjectPermission permission) { - - // Pull set of permissions for given object - String id = permission.getObjectIdentifier(); - EnumSet types = permissions.get(id); - - // If set does not yet exist, create it - if (types == null) { - types = EnumSet.of(permission.getType()); - permissions.put(id, types); - } - - // Otherwise, add the specified permission - else - types.add(permission.getType()); - - } - - /** - * Adds the given system-level permission to the given set of granted - * system permissions. - * - * @param permissions - * The set of system permissions to add the given permission to. - * - * @param permission - * The permission to add. - */ - private void addPermission(EnumSet permissions, SystemPermission permission) { - permissions.add(permission.getType()); - } - - /** - * Adds the given permission to the appropriate type-specific set or map of - * permissions based on the permission class. Only connection, connection - * group, user, and system permissions are supported. Unsupported - * permission types will result in a GuacamoleException being thrown. - * - * @param permission The permission to add. - * @throws GuacamoleException If the permission is of an unsupported type. - */ - private void addPermission(Permission permission) throws GuacamoleException { - - // Connection permissions - if (permission instanceof ConnectionPermission) - addPermission(connectionPermissions, (ConnectionPermission) permission); - - // Connection group permissions - else if (permission instanceof ConnectionGroupPermission) - addPermission(connectionGroupPermissions, (ConnectionGroupPermission) permission); - - // User permissions - else if (permission instanceof UserPermission) - addPermission(userPermissions, (UserPermission) permission); - - // System permissions - else if (permission instanceof SystemPermission) - addPermission(systemPermissions, (SystemPermission) permission); - - // Unknown / unsupported permission type - else - throw new GuacamoleServerException("Serialization of permission type \"" + permission.getClass() + "\" not implemented."); - - } + private Set systemPermissions = + EnumSet.noneOf(SystemPermission.Type.class); /** * Creates a new permission set which contains no granted permissions. Any @@ -151,37 +77,83 @@ public class APIPermissionSet { } /** - * Creates a new permission set having the given permissions. + * Adds the system permissions from the given SystemPermissionSet to the + * Set of system permissions provided. * * @param permissions - * The permissions to initially store within the permission set. + * The Set to add system permissions to. + * + * @param permSet + * The SystemPermissionSet containing the system permissions to add. * * @throws GuacamoleException - * If any of the given permissions are of an unsupported type. + * If an error occurs while retrieving system permissions from the + * SystemPermissionSet. */ - public APIPermissionSet(Iterable permissions) throws GuacamoleException { + private void addSystemPermissions(Set permissions, + SystemPermissionSet permSet) throws GuacamoleException { - // Add all provided permissions - for (Permission permission : permissions) - addPermission(permission); + // Add all provided system permissions + for (SystemPermission permission : permSet.getPermissions()) + permissions.add(permission.getType()); } - + /** - * Creates a new permission set having the given permissions. + * Adds the object permissions from the given ObjectPermissionSet to the + * Map of object permissions provided. * * @param permissions - * The permissions to initially store within the permission set. + * The Map to add object permissions to. + * + * @param permSet + * The ObjectPermissionSet containing the object permissions to add. * * @throws GuacamoleException - * If any of the given permissions are of an unsupported type. + * If an error occurs while retrieving object permissions from the + * ObjectPermissionSet. */ - public APIPermissionSet(Permission... permissions) throws GuacamoleException { + private void addObjectPermissions(Map> permissions, + ObjectPermissionSet permSet) throws GuacamoleException { - // Add all provided permissions - for (Permission permission : permissions) - addPermission(permission); + // Add all provided object permissions + for (ObjectPermission permission : permSet.getPermissions()) { + // Get associated set of permissions + String identifier = permission.getObjectIdentifier(); + Set objectPermissions = permissions.get(identifier); + + // Create new set if none yet exists + if (objectPermissions == null) + permissions.put(identifier, EnumSet.of(permission.getType())); + + // Otherwise add to existing set + else + objectPermissions.add(permission.getType()); + + } + + } + + /** + * Creates a new permission set containing all permissions currently + * granted to the given user. + * + * @param user + * The user whose permissions should be stored within this permission + * set. + * + * @throws GuacamoleException + * If an error occurs while retrieving the user's permissions. + */ + public APIPermissionSet(User user) throws GuacamoleException { + + // Add all permissions from the provided user + addSystemPermissions(systemPermissions, user.getSystemPermissions()); + addObjectPermissions(connectionPermissions, user.getConnectionPermissions()); + addObjectPermissions(connectionGroupPermissions, user.getConnectionGroupPermissions()); + addObjectPermissions(userPermissions, user.getUserPermissions()); + } /** @@ -195,7 +167,7 @@ public class APIPermissionSet { * A map of connection IDs to the set of permissions granted for that * connection. */ - public Map> getConnectionPermissions() { + public Map> getConnectionPermissions() { return connectionPermissions; } @@ -210,7 +182,7 @@ public class APIPermissionSet { * A map of connection group IDs to the set of permissions granted for * that connection group. */ - public Map> getConnectionGroupPermissions() { + public Map> getConnectionGroupPermissions() { return connectionGroupPermissions; } @@ -223,7 +195,7 @@ public class APIPermissionSet { * @return * A map of user IDs to the set of permissions granted for that user. */ - public Map> getUserPermissions() { + public Map> getUserPermissions() { return userPermissions; } @@ -236,7 +208,7 @@ public class APIPermissionSet { * @return * The set of granted system-level permissions. */ - public EnumSet getSystemPermissions() { + public Set getSystemPermissions() { return systemPermissions; } @@ -249,7 +221,7 @@ public class APIPermissionSet { * @param connectionPermissions * The map which must replace the currently-stored map of permissions. */ - public void setConnectionPermissions(Map> connectionPermissions) { + public void setConnectionPermissions(Map> connectionPermissions) { this.connectionPermissions = connectionPermissions; } @@ -262,7 +234,7 @@ public class APIPermissionSet { * @param connectionGroupPermissions * The map which must replace the currently-stored map of permissions. */ - public void setConnectionGroupPermissions(Map> connectionGroupPermissions) { + public void setConnectionGroupPermissions(Map> connectionGroupPermissions) { this.connectionGroupPermissions = connectionGroupPermissions; } @@ -274,7 +246,7 @@ public class APIPermissionSet { * @param userPermissions * The map which must replace the currently-stored map of permissions. */ - public void setUserPermissions(Map> userPermissions) { + public void setUserPermissions(Map> userPermissions) { this.userPermissions = userPermissions; } @@ -286,7 +258,7 @@ public class APIPermissionSet { * @param systemPermissions * The set which must replace the currently-stored set of permissions. */ - public void setSystemPermissions(EnumSet systemPermissions) { + public void setSystemPermissions(Set systemPermissions) { this.systemPermissions = systemPermissions; } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/APIUserWrapper.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/APIUserWrapper.java index dec5a9a65..d6032bbd2 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/APIUserWrapper.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/APIUserWrapper.java @@ -22,15 +22,17 @@ package org.glyptodon.guacamole.net.basic.rest.user; -import java.util.Collections; -import java.util.Set; import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.GuacamoleUnsupportedException; import org.glyptodon.guacamole.net.auth.User; -import org.glyptodon.guacamole.net.auth.permission.Permission; +import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet; +import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet; /** - * A wrapper to make an APIConnection look like a User. Useful where a - * org.glyptodon.guacamole.net.auth.User is required. + * A wrapper to make an APIUser look like a User. Useful where an + * org.glyptodon.guacamole.net.auth.User is required. As a simple wrapper for + * APIUser, access to permissions is not provided. Any attempt to access or + * manipulate permissions on an APIUserWrapper will result in an exception. * * @author James Muehlner */ @@ -41,12 +43,6 @@ public class APIUserWrapper implements User { */ private final APIUser apiUser; - /** - * The set of permissions for this user. - * NOTE: Not exposed by the REST endpoints. - */ - private Set permissionSet = Collections.EMPTY_SET; - /** * Wrap a given APIUser to expose as a User. * @param apiUser The APIUser to wrap. @@ -55,16 +51,6 @@ public class APIUserWrapper implements User { this.apiUser = apiUser; } - /** - * Wrap a given APIUser to expose as a User, with the given permission set. - * @param apiUser The APIUser to wrap. - * @param permissionSet The set of permissions for the wrapped user. - */ - public APIUserWrapper(APIUser apiUser, Set permissionSet) { - this.apiUser = apiUser; - this.permissionSet = permissionSet; - } - @Override public String getUsername() { return apiUser.getUsername(); @@ -86,23 +72,27 @@ public class APIUserWrapper implements User { } @Override - public Set getPermissions() throws GuacamoleException { - return permissionSet; + public SystemPermissionSet getSystemPermissions() + throws GuacamoleException { + throw new GuacamoleUnsupportedException("APIUserWrapper does not provide permission access."); } @Override - public boolean hasPermission(Permission permission) throws GuacamoleException { - return permissionSet.contains(permission); + public ObjectPermissionSet getConnectionPermissions() + throws GuacamoleException { + throw new GuacamoleUnsupportedException("APIUserWrapper does not provide permission access."); } @Override - public void addPermission(Permission permission) throws GuacamoleException { - throw new UnsupportedOperationException("Operation not supported."); + public ObjectPermissionSet getConnectionGroupPermissions() + throws GuacamoleException { + throw new GuacamoleUnsupportedException("APIUserWrapper does not provide permission access."); } @Override - public void removePermission(Permission permission) throws GuacamoleException { - throw new UnsupportedOperationException("Operation not supported."); + public ObjectPermissionSet getUserPermissions() + throws GuacamoleException { + throw new GuacamoleUnsupportedException("APIUserWrapper does not provide permission access."); } } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java index 8f12aff47..a0537656b 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java @@ -24,6 +24,7 @@ package org.glyptodon.guacamole.net.basic.rest.user; import com.google.inject.Inject; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.UUID; import javax.ws.rs.Consumes; @@ -43,12 +44,12 @@ import org.glyptodon.guacamole.GuacamoleResourceNotFoundException; import org.glyptodon.guacamole.net.auth.Directory; import org.glyptodon.guacamole.net.auth.User; import org.glyptodon.guacamole.net.auth.UserContext; -import org.glyptodon.guacamole.net.auth.permission.ConnectionGroupPermission; -import org.glyptodon.guacamole.net.auth.permission.ConnectionPermission; import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; +import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet; import org.glyptodon.guacamole.net.auth.permission.Permission; +import org.glyptodon.guacamole.net.auth.permission.PermissionSet; import org.glyptodon.guacamole.net.auth.permission.SystemPermission; -import org.glyptodon.guacamole.net.auth.permission.UserPermission; +import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet; import org.glyptodon.guacamole.net.basic.rest.APIPatch; import static org.glyptodon.guacamole.net.basic.rest.APIPatch.Operation.add; import static org.glyptodon.guacamole.net.basic.rest.APIPatch.Operation.remove; @@ -132,13 +133,13 @@ public class UserRESTService { private boolean hasUserPermission(User user, String username, List permissions) throws GuacamoleException { + // Retrieve user permissions + ObjectPermissionSet userPermissions = user.getUserPermissions(); + // Determine whether user has at least one of the given permissions for (ObjectPermission.Type permission : permissions) { - - UserPermission userPermission = new UserPermission(permission, username); - if (user.hasPermission(userPermission)) + if (userPermissions.hasPermission(permission, username)) return true; - } // None of the given permissions were present @@ -181,7 +182,8 @@ public class UserRESTService { permissions = null; // An admin user has access to any user - boolean isAdmin = self.hasPermission(new SystemPermission(SystemPermission.Type.ADMINISTER)); + SystemPermissionSet systemPermissions = self.getSystemPermissions(); + boolean isAdmin = systemPermissions.hasPermission(SystemPermission.Type.ADMINISTER); // Get the directory Directory userDirectory = userContext.getUserDirectory(); @@ -379,7 +381,53 @@ public class UserRESTService { throw new GuacamoleResourceNotFoundException("No such user: \"" + username + "\""); } - return new APIPermissionSet(user.getPermissions()); + return new APIPermissionSet(user); + + } + + /** + * Updates the given permission set by adding or removing the given + * permission based on the given patch operation. + * + * @param + * The type of permission stored within the permission set. + * + * @param operation + * The patch operation to perform. + * + * @param permissionSet + * The permission set being modified. + * + * @param permission + * The permission being added or removed from the set. + * + * @throws GuacamoleException + * If an error occurs while modifying the permission set. + */ + private void updatePermissionSet( + APIPatch.Operation operation, + PermissionSet permissionSet, + PermissionType permission) throws GuacamoleException { + + // Add or remove permission based on operation + switch (operation) { + + // Add permission + case add: + permissionSet.addPermissions(Collections.singleton(permission)); + break; + + // Remove permission + case remove: + permissionSet.removePermissions(Collections.singleton(permission)); + break; + + // Unsupported patch operation + default: + throw new HTTPException(Status.BAD_REQUEST, + "Unsupported patch operation: \"" + operation + "\""); + + } } @@ -423,8 +471,6 @@ public class UserRESTService { // Apply all patch operations individually for (APIPatch patch : patches) { - Permission permission; - String path = patch.getPath(); // Create connection permission if path has connection prefix @@ -434,8 +480,9 @@ public class UserRESTService { String identifier = path.substring(CONNECTION_PERMISSION_PATCH_PATH_PREFIX.length()); ObjectPermission.Type type = ObjectPermission.Type.valueOf(patch.getValue()); - // Create corresponding permission - permission = new ConnectionPermission(type, identifier); + // Create and update corresponding permission + ObjectPermission permission = new ObjectPermission(type, identifier); + updatePermissionSet(patch.getOp(), user.getConnectionPermissions(), permission); } @@ -446,8 +493,9 @@ public class UserRESTService { String identifier = path.substring(CONNECTION_GROUP_PERMISSION_PATCH_PATH_PREFIX.length()); ObjectPermission.Type type = ObjectPermission.Type.valueOf(patch.getValue()); - // Create corresponding permission - permission = new ConnectionGroupPermission(type, identifier); + // Create and update corresponding permission + ObjectPermission permission = new ObjectPermission(type, identifier); + updatePermissionSet(patch.getOp(), user.getConnectionGroupPermissions(), permission); } @@ -458,9 +506,10 @@ public class UserRESTService { String identifier = path.substring(USER_PERMISSION_PATCH_PATH_PREFIX.length()); ObjectPermission.Type type = ObjectPermission.Type.valueOf(patch.getValue()); - // Create corresponding permission - permission = new UserPermission(type, identifier); - + // Create and update corresponding permission + ObjectPermission permission = new ObjectPermission(type, identifier); + updatePermissionSet(patch.getOp(), user.getUserPermissions(), permission); + } // Create system permission if path is system path @@ -469,8 +518,9 @@ public class UserRESTService { // Get identifier and type from patch operation SystemPermission.Type type = SystemPermission.Type.valueOf(patch.getValue()); - // Create corresponding permission - permission = new SystemPermission(type); + // Create and update corresponding permission + SystemPermission permission = new SystemPermission(type); + updatePermissionSet(patch.getOp(), user.getSystemPermissions(), permission); } @@ -478,26 +528,6 @@ public class UserRESTService { else throw new HTTPException(Status.BAD_REQUEST, "Unsupported patch path: \"" + path + "\""); - // Add or remove permission based on operation - switch (patch.getOp()) { - - // Add permission - case add: - user.addPermission(permission); - break; - - // Remove permission - case remove: - user.removePermission(permission); - break; - - // Unsupported patch operation - default: - throw new HTTPException(Status.BAD_REQUEST, - "Unsupported patch operation: \"" + patch.getOp() + "\""); - - } - } // end for each patch operation // Save the permission changes From 433d55d2450899be7efa4e3b382b02b27da672a9 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 11 Feb 2015 19:40:07 -0800 Subject: [PATCH 10/19] GUAC-1100: Use getAll() for retrieval of multiple users. --- .../net/basic/rest/user/UserRESTService.java | 59 +++++-------------- 1 file changed, 14 insertions(+), 45 deletions(-) diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java index a0537656b..271941325 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java @@ -24,6 +24,7 @@ package org.glyptodon.guacamole.net.basic.rest.user; import com.google.inject.Inject; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.UUID; @@ -113,40 +114,6 @@ public class UserRESTService { @Inject private ObjectRetrievalService retrievalService; - /** - * Determines whether the given user has at least one of the given - * permissions for the user having the given username. - * - * @param user - * The user to check permissions for. - * - * @param username - * The username of the user to check permissions for. - * - * @param permissions - * The permissions to check. The given user must have one or more of - * these permissions for this function to return true. - * - * @return - * true if the user has at least one of the given permissions. - */ - private boolean hasUserPermission(User user, String username, - List permissions) throws GuacamoleException { - - // Retrieve user permissions - ObjectPermissionSet userPermissions = user.getUserPermissions(); - - // Determine whether user has at least one of the given permissions - for (ObjectPermission.Type permission : permissions) { - if (userPermissions.hasPermission(permission, username)) - return true; - } - - // None of the given permissions were present - return false; - - } - /** * Gets a list of users in the system, filtering the returned list by the * given permission, if specified. @@ -188,18 +155,20 @@ public class UserRESTService { // Get the directory Directory userDirectory = userContext.getUserDirectory(); - List users = new ArrayList(); - - // Add all users matching the given permission filter - for (String username : userDirectory.getIdentifiers()) { - - if (isAdmin || permissions == null || hasUserPermission(self, username, permissions)) - users.add(new APIUser(userDirectory.get(username))); - + // Filter users, if requested + Collection userIdentifiers = userDirectory.getIdentifiers(); + if (!isAdmin && permissions != null) { + ObjectPermissionSet userPermissions = self.getUserPermissions(); + userIdentifiers = userPermissions.getAccessibleObjects(permissions, userIdentifiers); } - - // Return the user directory listing - return users; + + // Retrieve all users, converting to API users + List apiUsers = new ArrayList(); + for (User user : userDirectory.getAll(userIdentifiers)) + apiUsers.add(new APIUser(user)); + + // Return the converted user list + return apiUsers; } From 514aafbd6ddaad548bcb31462e09d8ebe34d274e Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 11 Feb 2015 20:19:53 -0800 Subject: [PATCH 11/19] GUAC-1100: Implement patching of permissions with batch operations. --- .../basic/rest/user/PermissionSetPatch.java | 98 +++++++++++++++++++ .../net/basic/rest/user/UserRESTService.java | 43 ++++---- 2 files changed, 120 insertions(+), 21 deletions(-) create mode 100644 guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/PermissionSetPatch.java diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/PermissionSetPatch.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/PermissionSetPatch.java new file mode 100644 index 000000000..cb887e64e --- /dev/null +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/PermissionSetPatch.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.net.basic.rest.user; + +import java.util.HashSet; +import java.util.Set; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.net.auth.permission.Permission; +import org.glyptodon.guacamole.net.auth.permission.PermissionSet; + +/** + * A set of changes to be applied to a PermissionSet, describing the set of + * permissions being added and removed. + * + * @author Michael Jumper + * @param + * The type of permissions being added and removed. + */ +public class PermissionSetPatch { + + /** + * The set of all permissions being added. + */ + private final Set addedPermissions = + new HashSet(); + + /** + * The set of all permissions being removed. + */ + private final Set removedPermissions = + new HashSet(); + + /** + * Queues the given permission to be added. The add operation will be + * performed only when apply() is called. + * + * @param permission + * The permission to add. + */ + public void addPermission(PermissionType permission) { + addedPermissions.add(permission); + } + + /** + * Queues the given permission to be removed. The remove operation will be + * performed only when apply() is called. + * + * @param permission + * The permission to remove. + */ + public void removePermission(PermissionType permission) { + removedPermissions.add(permission); + } + + /** + * Applies all queued changes to the given permission set. + * + * @param permissionSet + * The permission set to add and remove permissions from. + * + * @throws GuacamoleException + * If an error occurs while manipulating the permissions of the given + * permission set. + */ + public void apply(PermissionSet permissionSet) + throws GuacamoleException { + + // Add any added permissions + if (!addedPermissions.isEmpty()) + permissionSet.addPermissions(addedPermissions); + + // Remove any removed permissions + if (!removedPermissions.isEmpty()) + permissionSet.removePermissions(removedPermissions); + + } + +} diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java index 271941325..109863540 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java @@ -25,7 +25,6 @@ package org.glyptodon.guacamole.net.basic.rest.user; import com.google.inject.Inject; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.UUID; import javax.ws.rs.Consumes; @@ -48,7 +47,6 @@ import org.glyptodon.guacamole.net.auth.UserContext; import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet; import org.glyptodon.guacamole.net.auth.permission.Permission; -import org.glyptodon.guacamole.net.auth.permission.PermissionSet; import org.glyptodon.guacamole.net.auth.permission.SystemPermission; import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet; import org.glyptodon.guacamole.net.basic.rest.APIPatch; @@ -355,8 +353,8 @@ public class UserRESTService { } /** - * Updates the given permission set by adding or removing the given - * permission based on the given patch operation. + * Updates the given permission set patch by queuing an add or remove + * operation for the given permission based on the given patch operation. * * @param * The type of permission stored within the permission set. @@ -364,31 +362,28 @@ public class UserRESTService { * @param operation * The patch operation to perform. * - * @param permissionSet - * The permission set being modified. + * @param permissionSetPatch + * The permission set patch being modified. * * @param permission * The permission being added or removed from the set. - * - * @throws GuacamoleException - * If an error occurs while modifying the permission set. */ private void updatePermissionSet( APIPatch.Operation operation, - PermissionSet permissionSet, - PermissionType permission) throws GuacamoleException { + PermissionSetPatch permissionSetPatch, + PermissionType permission) { // Add or remove permission based on operation switch (operation) { // Add permission case add: - permissionSet.addPermissions(Collections.singleton(permission)); + permissionSetPatch.addPermission(permission); break; // Remove permission case remove: - permissionSet.removePermissions(Collections.singleton(permission)); + permissionSetPatch.removePermission(permission); break; // Unsupported patch operation @@ -429,14 +424,17 @@ public class UserRESTService { UserContext userContext = authenticationService.getUserContext(authToken); - // Get the user directory - Directory userDirectory = userContext.getUserDirectory(); - // Get the user User user = userContext.getUserDirectory().get(username); if (user == null) throw new GuacamoleResourceNotFoundException("No such user: \"" + username + "\""); + // Permission patches for all types of permissions + PermissionSetPatch> connectionPermissionPatch = new PermissionSetPatch>(); + PermissionSetPatch> connectionGroupPermissionPatch = new PermissionSetPatch>(); + PermissionSetPatch> userPermissionPatch = new PermissionSetPatch>(); + PermissionSetPatch systemPermissionPatch = new PermissionSetPatch(); + // Apply all patch operations individually for (APIPatch patch : patches) { @@ -451,7 +449,7 @@ public class UserRESTService { // Create and update corresponding permission ObjectPermission permission = new ObjectPermission(type, identifier); - updatePermissionSet(patch.getOp(), user.getConnectionPermissions(), permission); + updatePermissionSet(patch.getOp(), connectionPermissionPatch, permission); } @@ -464,7 +462,7 @@ public class UserRESTService { // Create and update corresponding permission ObjectPermission permission = new ObjectPermission(type, identifier); - updatePermissionSet(patch.getOp(), user.getConnectionGroupPermissions(), permission); + updatePermissionSet(patch.getOp(), connectionGroupPermissionPatch, permission); } @@ -477,7 +475,7 @@ public class UserRESTService { // Create and update corresponding permission ObjectPermission permission = new ObjectPermission(type, identifier); - updatePermissionSet(patch.getOp(), user.getUserPermissions(), permission); + updatePermissionSet(patch.getOp(), userPermissionPatch, permission); } @@ -489,7 +487,7 @@ public class UserRESTService { // Create and update corresponding permission SystemPermission permission = new SystemPermission(type); - updatePermissionSet(patch.getOp(), user.getSystemPermissions(), permission); + updatePermissionSet(patch.getOp(), systemPermissionPatch, permission); } @@ -500,7 +498,10 @@ public class UserRESTService { } // end for each patch operation // Save the permission changes - userDirectory.update(user); + connectionPermissionPatch.apply(user.getConnectionPermissions()); + connectionGroupPermissionPatch.apply(user.getConnectionGroupPermissions()); + userPermissionPatch.apply(user.getUserPermissions()); + systemPermissionPatch.apply(user.getSystemPermissions()); } From 37227d05e837500f653be7883d65fa92fab902a6 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Wed, 11 Feb 2015 20:24:46 -0800 Subject: [PATCH 12/19] GUAC-1100: System path comparison should not be startsWith() - there's only one, and no identifiers. --- .../guacamole/net/basic/rest/user/UserRESTService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java index 109863540..b9345ce45 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java @@ -480,7 +480,7 @@ public class UserRESTService { } // Create system permission if path is system path - else if (path.startsWith(SYSTEM_PERMISSION_PATCH_PATH)) { + else if (path.equals(SYSTEM_PERMISSION_PATCH_PATH)) { // Get identifier and type from patch operation SystemPermission.Type type = SystemPermission.Type.valueOf(patch.getValue()); From e9538a4167f8edc381bbd355aef29bf3b4076866 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 12 Feb 2015 23:07:45 -0800 Subject: [PATCH 13/19] GUAC-1100: Commit to String identifiers. --- .../guacamole/net/auth/AbstractUser.java | 4 +- .../guacamole/net/auth/Connection.java | 20 +------ .../guacamole/net/auth/ConnectionGroup.java | 47 +++++++++-------- .../guacamole/net/auth/Directory.java | 17 +++--- .../guacamole/net/auth/Identifiable.java | 52 +++++++++++++++++++ .../glyptodon/guacamole/net/auth/User.java | 25 ++------- .../guacamole/net/auth/UserContext.java | 2 +- .../net/auth/permission/ObjectPermission.java | 10 ++-- .../auth/permission/ObjectPermissionSet.java | 22 ++++---- .../simple/SimpleConnectionDirectory.java | 2 +- .../auth/simple/SimpleConnectionGroup.java | 12 ++--- .../SimpleConnectionGroupDirectory.java | 2 +- .../net/auth/simple/SimpleDirectory.java | 28 ++++------ .../simple/SimpleObjectPermissionSet.java | 38 ++++++-------- .../guacamole/net/auth/simple/SimpleUser.java | 24 ++++----- .../net/auth/simple/SimpleUserContext.java | 4 +- .../net/auth/simple/SimpleUserDirectory.java | 4 +- .../net/basic/TunnelRequestService.java | 12 ++--- .../basic/rest/ObjectRetrievalService.java | 6 +-- .../net/basic/rest/auth/TokenRESTService.java | 4 +- .../connection/ConnectionRESTService.java | 8 +-- .../APIConnectionGroupWrapper.java | 4 +- .../ConnectionGroupRESTService.java | 14 ++--- .../rest/permission/APIPermissionSet.java | 4 +- .../net/basic/rest/user/APIUser.java | 2 +- .../net/basic/rest/user/APIUserWrapper.java | 10 ++-- .../net/basic/rest/user/UserRESTService.java | 26 +++++----- 27 files changed, 201 insertions(+), 202 deletions(-) create mode 100644 guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Identifiable.java diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/AbstractUser.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/AbstractUser.java index 96cdb619e..d3232b6cb 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/AbstractUser.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/AbstractUser.java @@ -44,12 +44,12 @@ public abstract class AbstractUser implements User { private String password; @Override - public String getUsername() { + public String getIdentifier() { return username; } @Override - public void setUsername(String username) { + public void setIdentifier(String username) { this.username = username; } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connection.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connection.java index cfd6447f2..63e60a328 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connection.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connection.java @@ -36,7 +36,7 @@ import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; * * @author Michael Jumper */ -public interface Connection { +public interface Connection extends Identifiable { /** * Returns the name assigned to this Connection. @@ -51,24 +51,6 @@ public interface Connection { */ public void setName(String name); - /** - * Returns the unique identifier assigned to this Connection. All - * connections must have a deterministic, unique identifier which may not - * be null. - * - * @return - * The unique identifier assigned to this Connection, which may not be - * null. - */ - public String getIdentifier(); - - /** - * Sets the identifier assigned to this Connection. - * - * @param identifier The identifier to assign. - */ - public void setIdentifier(String identifier); - /** * Returns the unique identifier of the parent ConnectionGroup for * this Connection. diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionGroup.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionGroup.java index 6b5f84712..a99978759 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionGroup.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionGroup.java @@ -32,10 +32,29 @@ import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; * * @author James Muehlner */ -public interface ConnectionGroup { - +public interface ConnectionGroup extends Identifiable { + + /** + * All legal types of connection group. + */ public enum Type { - ORGANIZATIONAL, BALANCING + + /** + * A connection group that purely organizes other connections or + * connection groups, serving only as a container. An organizational + * connection group is analogous to a directory or folder in a + * filesystem. + */ + ORGANIZATIONAL, + + /** + * A connection group that acts as a load balancer. A balancing + * connection group can be connected to in the same manner as a + * connection, and will transparently route to the least-used + * underlying connection. + */ + BALANCING + }; /** @@ -51,24 +70,6 @@ public interface ConnectionGroup { */ public void setName(String name); - /** - * Returns the unique identifier assigned to this ConnectionGroup. All - * connection groups must have a deterministic, unique identifier which may - * not be null. - * - * @return - * The unique identifier assigned to this ConnectionGroup, which may - * not be null. - */ - public String getIdentifier(); - - /** - * Sets the identifier assigned to this ConnectionGroup. - * - * @param identifier The identifier to assign. - */ - public void setIdentifier(String identifier); - /** * Returns the unique identifier of the parent ConnectionGroup for * this ConnectionGroup. @@ -111,7 +112,7 @@ public interface ConnectionGroup { * @throws GuacamoleException If an error occurs while creating the * Directory. */ - Directory getConnectionDirectory() + Directory getConnectionDirectory() throws GuacamoleException; /** @@ -125,7 +126,7 @@ public interface ConnectionGroup { * @throws GuacamoleException If an error occurs while creating the * Directory. */ - Directory getConnectionGroupDirectory() + Directory getConnectionGroupDirectory() throws GuacamoleException; /** diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Directory.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Directory.java index 96f4f7b02..b241c017e 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Directory.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Directory.java @@ -34,11 +34,10 @@ import org.glyptodon.guacamole.GuacamoleException; * function. * * @author Michael Jumper - * @param The type of identifier used to identify objects - * stored within this Directory. - * @param The type of objects stored within this Directory. + * @param + * The type of objects stored within this Directory. */ -public interface Directory { +public interface Directory { /** * Returns the object having the given identifier. Note that changes to @@ -56,7 +55,7 @@ public interface Directory { * object, or if permission for retrieving the * object is denied. */ - ObjectType get(IdentifierType identifier) throws GuacamoleException; + ObjectType get(String identifier) throws GuacamoleException; /** * Returns the objects having the given identifiers. Note that changes to @@ -78,7 +77,7 @@ public interface Directory { * If an error occurs while retrieving the objects, or if permission * to retrieve the requested objects is denied. */ - Collection getAll(Collection identifiers) + Collection getAll(Collection identifiers) throws GuacamoleException; /** @@ -89,7 +88,7 @@ public interface Directory { * @throws GuacamoleException If an error occurs while retrieving * the identifiers. */ - Set getIdentifiers() throws GuacamoleException; + Set getIdentifiers() throws GuacamoleException; /** * Adds the given object to the overall set. @@ -121,7 +120,7 @@ public interface Directory { * @throws GuacamoleException If an error occurs while removing the object, * or if removing object is not allowed. */ - void remove(IdentifierType identifier) throws GuacamoleException; + void remove(String identifier) throws GuacamoleException; /** * Moves the object with the given identifier to the given directory. @@ -132,7 +131,7 @@ public interface Directory { * @throws GuacamoleException If an error occurs while moving the object, * or if moving object is not allowed. */ - void move(IdentifierType identifier, Directory directory) + void move(String identifier, Directory directory) throws GuacamoleException; } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Identifiable.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Identifiable.java new file mode 100644 index 000000000..8490bbf7c --- /dev/null +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Identifiable.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2013 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.net.auth; + +/** + * An object which has a deterministic, unique identifier, which may not be + * null. + * + * @author Michael Jumper + */ +public interface Identifiable { + + /** + * Returns the unique identifier assigned to this object. All identifiable + * objects must have a deterministic, unique identifier which may not be + * null. + * + * @return + * The unique identifier assigned to this object, which may not be + * null. + */ + public String getIdentifier(); + + /** + * Sets the identifier assigned to this object. + * + * @param identifier + * The identifier to assign. + */ + public void setIdentifier(String identifier); + +} diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/User.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/User.java index da5c632e4..09e4c2e78 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/User.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/User.java @@ -32,24 +32,7 @@ import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet; * * @author Michael Jumper */ -public interface User { - - /** - * Returns the name of this user, which must be unique across all users. - * All users must have a deterministic, unique username which may not be - * null. - * - * @return - * The unique username of this user, which may not be null. - */ - public String getUsername(); - - /** - * Sets the name of this user, which must be unique across all users. - * - * @param username The name of this user. - */ - public void setUsername(String username); +public interface User extends Identifiable { /** * Returns this user's password. Note that the password returned may be @@ -92,7 +75,7 @@ public interface User { * If an error occurs while retrieving permissions, or if reading all * permissions is not allowed. */ - ObjectPermissionSet getConnectionPermissions() + ObjectPermissionSet getConnectionPermissions() throws GuacamoleException; /** @@ -106,7 +89,7 @@ public interface User { * If an error occurs while retrieving permissions, or if reading all * permissions is not allowed. */ - ObjectPermissionSet getConnectionGroupPermissions() + ObjectPermissionSet getConnectionGroupPermissions() throws GuacamoleException; /** @@ -119,6 +102,6 @@ public interface User { * If an error occurs while retrieving permissions, or if reading all * permissions is not allowed. */ - ObjectPermissionSet getUserPermissions() throws GuacamoleException; + ObjectPermissionSet getUserPermissions() throws GuacamoleException; } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/UserContext.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/UserContext.java index 5912b38ec..deba2cb7d 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/UserContext.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/UserContext.java @@ -52,7 +52,7 @@ public interface UserContext { * @throws GuacamoleException If an error occurs while creating the * Directory. */ - Directory getUserDirectory() throws GuacamoleException; + Directory getUserDirectory() throws GuacamoleException; /** * Retrieves a connection group which can be used to view and manipulate diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermission.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermission.java index c776e3414..e0927f30a 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermission.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/permission/ObjectPermission.java @@ -28,10 +28,8 @@ package org.glyptodon.guacamole.net.auth.permission; * whole. * * @author Michael Jumper - * @param - * The type of identifier used by the object this permission affects. */ -public class ObjectPermission implements Permission { +public class ObjectPermission implements Permission { /** * Specific types of object-level permissions. Each permission type is @@ -65,7 +63,7 @@ public class ObjectPermission implements Permission implements Permission implements Permission - * The type of identifier used to identify objects affected by permissions - * stored in this ObjectPermissionSet. */ -public interface ObjectPermissionSet - extends PermissionSet> { +public interface ObjectPermissionSet extends PermissionSet { /** * Tests whether the permission of the given type is granted for the @@ -58,7 +54,7 @@ public interface ObjectPermissionSet * cannot be checked due to lack of permissions to do so. */ boolean hasPermission(ObjectPermission.Type permission, - IdentifierType identifier) throws GuacamoleException; + String identifier) throws GuacamoleException; /** * Adds the specified permission for the object having the given @@ -76,7 +72,7 @@ public interface ObjectPermissionSet * add permissions is denied. */ void addPermission(ObjectPermission.Type permission, - IdentifierType identifier) throws GuacamoleException; + String identifier) throws GuacamoleException; /** * Removes the specified permission for the object having the given @@ -94,7 +90,7 @@ public interface ObjectPermissionSet * to remove permissions is denied. */ void removePermission(ObjectPermission.Type permission, - IdentifierType identifier) throws GuacamoleException; + String identifier) throws GuacamoleException; /** * Tests whether this user has the specified permissions for the objects @@ -119,20 +115,20 @@ public interface ObjectPermissionSet * If an error occurs while checking permissions, or if permissions * cannot be checked due to lack of permissions to do so. */ - Collection getAccessibleObjects( + Collection getAccessibleObjects( Collection permissions, - Collection identifiers) throws GuacamoleException; + Collection identifiers) throws GuacamoleException; @Override - Set> getPermissions() + Set getPermissions() throws GuacamoleException; @Override - void addPermissions(Set> permissions) + void addPermissions(Set permissions) throws GuacamoleException; @Override - void removePermissions(Set> permissions) + void removePermissions(Set permissions) throws GuacamoleException; } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionDirectory.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionDirectory.java index e7669b872..a8641cb6c 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionDirectory.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionDirectory.java @@ -35,7 +35,7 @@ import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; * * @author Michael Jumper */ -public class SimpleConnectionDirectory extends SimpleDirectory { +public class SimpleConnectionDirectory extends SimpleDirectory { /** * The Map of Connections to provide access to. diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroup.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroup.java index ffcf7a34a..6f4cb1051 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroup.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroup.java @@ -44,13 +44,13 @@ public class SimpleConnectionGroup extends AbstractConnectionGroup { * Underlying connection directory, containing all connections within this * group. */ - private final Directory connectionDirectory; + private final Directory connectionDirectory; /** * Underlying connection group directory, containing all connections within * this group. */ - private final Directory connectionGroupDirectory; + private final Directory connectionGroupDirectory; /** * Creates a new SimpleConnectionGroup having the given name and identifier @@ -64,8 +64,8 @@ public class SimpleConnectionGroup extends AbstractConnectionGroup { * when requested. */ public SimpleConnectionGroup(String name, String identifier, - Directory connectionDirectory, - Directory connectionGroupDirectory) { + Directory connectionDirectory, + Directory connectionGroupDirectory) { // Set name setName(name); @@ -83,13 +83,13 @@ public class SimpleConnectionGroup extends AbstractConnectionGroup { } @Override - public Directory getConnectionDirectory() + public Directory getConnectionDirectory() throws GuacamoleException { return connectionDirectory; } @Override - public Directory getConnectionGroupDirectory() + public Directory getConnectionGroupDirectory() throws GuacamoleException { return connectionGroupDirectory; } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroupDirectory.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroupDirectory.java index 344cbcb4d..8e0a6d6f8 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroupDirectory.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroupDirectory.java @@ -35,7 +35,7 @@ import org.glyptodon.guacamole.net.auth.ConnectionGroup; * @author James Muehlner */ public class SimpleConnectionGroupDirectory - extends SimpleDirectory { + extends SimpleDirectory { /** * The Map of ConnectionGroups to provide access to. diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleDirectory.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleDirectory.java index d665a9687..570fe2bcd 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleDirectory.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleDirectory.java @@ -37,20 +37,15 @@ import org.glyptodon.guacamole.net.auth.Directory; * will affect the available contents of this SimpleDirectory. * * @author Michael Jumper - * @param - * The type of identifier used to identify objects stored within this - * SimpleDirectory. - * * @param * The type of objects stored within this SimpleDirectory. */ -public class SimpleDirectory - implements Directory { +public class SimpleDirectory implements Directory { /** * The Map of objects to provide access to. */ - private Map objects = Collections.EMPTY_MAP; + private Map objects = Collections.EMPTY_MAP; /** * Creates a new empty SimpleDirectory which does not provide access to @@ -66,7 +61,7 @@ public class SimpleDirectory * @param objects * The Map of objects to provide access to. */ - public SimpleDirectory(Map objects) { + public SimpleDirectory(Map objects) { this.objects = objects; } @@ -78,7 +73,7 @@ public class SimpleDirectory * @param objects * The Map of objects to provide access to. */ - protected void setObjects(Map objects) { + protected void setObjects(Map objects) { this.objects = objects; } @@ -90,25 +85,25 @@ public class SimpleDirectory * @return * The Map of objects which currently backs this SimpleDirectory. */ - protected Map getObjects() { + protected Map getObjects() { return objects; } @Override - public ObjectType get(IdentifierType identifier) + public ObjectType get(String identifier) throws GuacamoleException { return objects.get(identifier); } @Override - public Collection getAll(Collection identifiers) + public Collection getAll(Collection identifiers) throws GuacamoleException { // Create collection which has an appropriate initial size Collection foundObjects = new ArrayList(identifiers.size()); // Populate collection with matching objects - for (IdentifierType identifier : identifiers) { + for (String identifier : identifiers) { // Add the object which has the current identifier, if any ObjectType object = objects.get(identifier); @@ -122,7 +117,7 @@ public class SimpleDirectory } @Override - public Set getIdentifiers() throws GuacamoleException { + public Set getIdentifiers() throws GuacamoleException { return objects.keySet(); } @@ -139,13 +134,12 @@ public class SimpleDirectory } @Override - public void remove(IdentifierType identifier) throws GuacamoleException { + public void remove(String identifier) throws GuacamoleException { throw new GuacamoleSecurityException("Permission denied."); } @Override - public void move(IdentifierType identifier, - Directory directory) + public void move(String identifier, Directory directory) throws GuacamoleException { throw new GuacamoleSecurityException("Permission denied."); } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleObjectPermissionSet.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleObjectPermissionSet.java index 96a98b46a..b265ca5ca 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleObjectPermissionSet.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleObjectPermissionSet.java @@ -36,17 +36,13 @@ import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet; * of Permissions to determine which permissions are present. * * @author Michael Jumper - * @param - * The type of identifier used to identify objects affected by permissions - * stored in this SimpleObjectPermissionSet. */ -public class SimpleObjectPermissionSet - implements ObjectPermissionSet { +public class SimpleObjectPermissionSet implements ObjectPermissionSet { /** * The set of all permissions currently granted. */ - private Set> permissions = Collections.EMPTY_SET; + private Set permissions = Collections.EMPTY_SET; /** * Creates a new empty SimpleObjectPermissionSet. @@ -62,7 +58,7 @@ public class SimpleObjectPermissionSet * The Set of permissions this SimpleObjectPermissionSet should * contain. */ - public SimpleObjectPermissionSet(Set> permissions) { + public SimpleObjectPermissionSet(Set permissions) { this.permissions = permissions; } @@ -74,21 +70,21 @@ public class SimpleObjectPermissionSet * The Set of permissions this SimpleObjectPermissionSet should * contain. */ - protected void setPermissions(Set> permissions) { + protected void setPermissions(Set permissions) { this.permissions = permissions; } @Override - public Set> getPermissions() { + public Set getPermissions() { return permissions; } @Override public boolean hasPermission(ObjectPermission.Type permission, - IdentifierType identifier) throws GuacamoleException { + String identifier) throws GuacamoleException { - ObjectPermission objectPermission = - new ObjectPermission(permission, identifier); + ObjectPermission objectPermission = + new ObjectPermission(permission, identifier); return permissions.contains(objectPermission); @@ -96,29 +92,29 @@ public class SimpleObjectPermissionSet @Override public void addPermission(ObjectPermission.Type permission, - IdentifierType identifier) throws GuacamoleException { + String identifier) throws GuacamoleException { throw new GuacamoleSecurityException("Permission denied."); } @Override public void removePermission(ObjectPermission.Type permission, - IdentifierType identifier) throws GuacamoleException { + String identifier) throws GuacamoleException { throw new GuacamoleSecurityException("Permission denied."); } @Override - public Collection getAccessibleObjects( + public Collection getAccessibleObjects( Collection permissionTypes, - Collection identifiers) throws GuacamoleException { + Collection identifiers) throws GuacamoleException { - Collection accessibleObjects = new ArrayList(permissions.size()); + Collection accessibleObjects = new ArrayList(permissions.size()); // For each identifier/permission combination - for (IdentifierType identifier : identifiers) { + for (String identifier : identifiers) { for (ObjectPermission.Type permissionType : permissionTypes) { // Add identifier if at least one requested permission is granted - ObjectPermission permission = new ObjectPermission(permissionType, identifier); + ObjectPermission permission = new ObjectPermission(permissionType, identifier); if (permissions.contains(permission)) { accessibleObjects.add(identifier); break; @@ -132,13 +128,13 @@ public class SimpleObjectPermissionSet } @Override - public void addPermissions(Set> permissions) + public void addPermissions(Set permissions) throws GuacamoleException { throw new GuacamoleSecurityException("Permission denied."); } @Override - public void removePermissions(Set> permissions) + public void removePermissions(Set permissions) throws GuacamoleException { throw new GuacamoleSecurityException("Permission denied."); } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java index 0e75527e5..873c59062 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java @@ -28,9 +28,7 @@ import java.util.Map; import java.util.Set; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.net.auth.AbstractUser; -import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionGroup; -import org.glyptodon.guacamole.net.auth.User; import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet; import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet; @@ -46,14 +44,14 @@ public class SimpleUser extends AbstractUser { /** * All connection permissions granted to this user. */ - private final Set> connectionPermissions = - new HashSet>(); + private final Set connectionPermissions = + new HashSet(); /** * All connection group permissions granted to this user. */ - private final Set> connectionGroupPermissions = - new HashSet>(); + private final Set connectionGroupPermissions = + new HashSet(); /** * Creates a completely uninitialized SimpleUser. @@ -73,7 +71,7 @@ public class SimpleUser extends AbstractUser { Collection groups) { // Set username - setUsername(username); + setIdentifier(username); // Add connection permissions for (String identifier : configs.keySet()) { @@ -112,21 +110,21 @@ public class SimpleUser extends AbstractUser { } @Override - public ObjectPermissionSet getConnectionPermissions() + public ObjectPermissionSet getConnectionPermissions() throws GuacamoleException { - return new SimpleObjectPermissionSet(connectionPermissions); + return new SimpleObjectPermissionSet(connectionPermissions); } @Override - public ObjectPermissionSet getConnectionGroupPermissions() + public ObjectPermissionSet getConnectionGroupPermissions() throws GuacamoleException { - return new SimpleObjectPermissionSet(connectionGroupPermissions); + return new SimpleObjectPermissionSet(connectionGroupPermissions); } @Override - public ObjectPermissionSet getUserPermissions() + public ObjectPermissionSet getUserPermissions() throws GuacamoleException { - return new SimpleObjectPermissionSet(); + return new SimpleObjectPermissionSet(); } } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java index 2bb376747..474bc5373 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java @@ -51,7 +51,7 @@ public class SimpleUserContext implements UserContext { * The Directory with access only to the User associated with this * UserContext. */ - private final Directory userDirectory; + private final Directory userDirectory; /** * The ConnectionGroup with access only to those Connections that the User @@ -102,7 +102,7 @@ public class SimpleUserContext implements UserContext { } @Override - public Directory getUserDirectory() + public Directory getUserDirectory() throws GuacamoleException { return userDirectory; } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserDirectory.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserDirectory.java index de7bd08e8..e44f1897e 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserDirectory.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserDirectory.java @@ -31,7 +31,7 @@ import org.glyptodon.guacamole.net.auth.User; * * @author Michael Jumper */ -public class SimpleUserDirectory extends SimpleDirectory { +public class SimpleUserDirectory extends SimpleDirectory { /** * Creates a new SimpleUserDirectory which provides access to the single @@ -40,7 +40,7 @@ public class SimpleUserDirectory extends SimpleDirectory { * @param user The user to provide access to. */ public SimpleUserDirectory(User user) { - super(Collections.singletonMap(user.getUsername(), user)); + super(Collections.singletonMap(user.getIdentifier(), user)); } } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/TunnelRequestService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/TunnelRequestService.java index 25e7c87fe..8c1679236 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/TunnelRequestService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/TunnelRequestService.java @@ -213,19 +213,19 @@ public class TunnelRequestService { UserContext context = session.getUserContext(); // Get connection directory - Directory directory = + Directory directory = context.getRootConnectionGroup().getConnectionDirectory(); // Get authorized connection Connection connection = directory.get(id); if (connection == null) { - logger.info("Connection \"{}\" does not exist for user \"{}\".", id, context.self().getUsername()); + logger.info("Connection \"{}\" does not exist for user \"{}\".", id, context.self().getIdentifier()); throw new GuacamoleSecurityException("Requested connection is not authorized."); } // Connect socket socket = connection.connect(info); - logger.info("User \"{}\" successfully connected to \"{}\".", context.self().getUsername(), id); + logger.info("User \"{}\" successfully connected to \"{}\".", context.self().getIdentifier(), id); break; } @@ -235,19 +235,19 @@ public class TunnelRequestService { UserContext context = session.getUserContext(); // Get connection group directory - Directory directory = + Directory directory = context.getRootConnectionGroup().getConnectionGroupDirectory(); // Get authorized connection group ConnectionGroup group = directory.get(id); if (group == null) { - logger.info("Connection group \"{}\" does not exist for user \"{}\".", id, context.self().getUsername()); + logger.info("Connection group \"{}\" does not exist for user \"{}\".", id, context.self().getIdentifier()); throw new GuacamoleSecurityException("Requested connection group is not authorized."); } // Connect socket socket = group.connect(info); - logger.info("User \"{}\" successfully connected to group \"{}\".", context.self().getUsername(), id); + logger.info("User \"{}\" successfully connected to group \"{}\".", context.self().getIdentifier(), id); break; } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/ObjectRetrievalService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/ObjectRetrievalService.java index 27cb6d9ef..fb7356604 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/ObjectRetrievalService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/ObjectRetrievalService.java @@ -59,7 +59,7 @@ public class ObjectRetrievalService { String identifier) throws GuacamoleException { // Get user directory - Directory directory = userContext.getUserDirectory(); + Directory directory = userContext.getUserDirectory(); // Pull specified user User user = directory.get(identifier); @@ -91,7 +91,7 @@ public class ObjectRetrievalService { // Get root directory ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); - Directory directory = rootGroup.getConnectionDirectory(); + Directory directory = rootGroup.getConnectionDirectory(); // Pull specified connection Connection connection = directory.get(identifier); @@ -132,7 +132,7 @@ public class ObjectRetrievalService { return rootGroup; // Pull specified connection group otherwise - Directory directory = rootGroup.getConnectionGroupDirectory(); + Directory directory = rootGroup.getConnectionGroupDirectory(); ConnectionGroup connectionGroup = directory.get(identifier); if (connectionGroup == null) diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/TokenRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/TokenRESTService.java index e46b54d1a..3aac87e65 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/TokenRESTService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/auth/TokenRESTService.java @@ -188,8 +188,8 @@ public class TokenRESTService { tokenSessionMap.put(authToken, new GuacamoleSession(credentials, userContext)); } - logger.debug("Login was successful for user \"{}\".", userContext.self().getUsername()); - return new APIAuthToken(authToken, userContext.self().getUsername()); + logger.debug("Login was successful for user \"{}\".", userContext.self().getIdentifier()); + return new APIAuthToken(authToken, userContext.self().getIdentifier()); } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionRESTService.java index 0ec05e3f0..5e1eb7368 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionRESTService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionRESTService.java @@ -139,7 +139,7 @@ public class ConnectionRESTService { // Retrieve permission sets SystemPermissionSet systemPermissions = self.getSystemPermissions(); - ObjectPermissionSet connectionPermissions = self.getConnectionPermissions(); + ObjectPermissionSet connectionPermissions = self.getConnectionPermissions(); // Deny access if adminstrative or update permission is missing if (!systemPermissions.hasPermission(SystemPermission.Type.ADMINISTER) @@ -211,7 +211,7 @@ public class ConnectionRESTService { // Get the connection directory ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); - Directory connectionDirectory = + Directory connectionDirectory = rootGroup.getConnectionDirectory(); // Delete the specified connection @@ -252,7 +252,7 @@ public class ConnectionRESTService { ConnectionGroup parentConnectionGroup = retrievalService.retrieveConnectionGroup(userContext, parentID); // Add the new connection - Directory connectionDirectory = parentConnectionGroup.getConnectionDirectory(); + Directory connectionDirectory = parentConnectionGroup.getConnectionDirectory(); connectionDirectory.add(new APIConnectionWrapper(connection)); // Return the new connection identifier @@ -292,7 +292,7 @@ public class ConnectionRESTService { // Get the connection directory ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); - Directory connectionDirectory = + Directory connectionDirectory = rootGroup.getConnectionDirectory(); // Retrieve connection to update diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java index c38b22977..24128bb56 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java @@ -92,12 +92,12 @@ public class APIConnectionGroupWrapper implements ConnectionGroup { } @Override - public Directory getConnectionDirectory() throws GuacamoleException { + public Directory getConnectionDirectory() throws GuacamoleException { throw new UnsupportedOperationException("Operation not supported."); } @Override - public Directory getConnectionGroupDirectory() throws GuacamoleException { + public Directory getConnectionGroupDirectory() throws GuacamoleException { throw new UnsupportedOperationException("Operation not supported."); } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java index 651ddbd85..22430bf84 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java @@ -104,7 +104,7 @@ public class ConnectionGroupRESTService { List permissions) throws GuacamoleException { // Retrieve connection permissions - ObjectPermissionSet connectionPermissions = user.getConnectionPermissions(); + ObjectPermissionSet connectionPermissions = user.getConnectionPermissions(); // Determine whether user has at least one of the given permissions for (ObjectPermission.Type permission : permissions) { @@ -138,7 +138,7 @@ public class ConnectionGroupRESTService { List permissions) throws GuacamoleException { // Retrieve connection group permissions - ObjectPermissionSet connectionGroupPermissions = user.getConnectionGroupPermissions(); + ObjectPermissionSet connectionGroupPermissions = user.getConnectionGroupPermissions(); // Determine whether user has at least one of the given permissions for (ObjectPermission.Type permission : permissions) { @@ -211,7 +211,7 @@ public class ConnectionGroupRESTService { // Query all child connections Collection apiConnections = new ArrayList(); - Directory connectionDirectory = connectionGroup.getConnectionDirectory(); + Directory connectionDirectory = connectionGroup.getConnectionDirectory(); for (String childIdentifier : connectionDirectory.getIdentifiers()) { @@ -231,7 +231,7 @@ public class ConnectionGroupRESTService { // Query all child connection groups Collection apiConnectionGroups = new ArrayList(); - Directory groupDirectory = connectionGroup.getConnectionGroupDirectory(); + Directory groupDirectory = connectionGroup.getConnectionGroupDirectory(); for (String childIdentifier : groupDirectory.getIdentifiers()) { @@ -356,7 +356,7 @@ public class ConnectionGroupRESTService { // Get the connection group directory ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); - Directory connectionGroupDirectory = + Directory connectionGroupDirectory = rootGroup.getConnectionGroupDirectory(); // Delete the connection group @@ -399,7 +399,7 @@ public class ConnectionGroupRESTService { ConnectionGroup parentConnectionGroup = retrievalService.retrieveConnectionGroup(userContext, parentID); // Add the new connection group - Directory connectionGroupDirectory = parentConnectionGroup.getConnectionGroupDirectory(); + Directory connectionGroupDirectory = parentConnectionGroup.getConnectionGroupDirectory(); connectionGroupDirectory.add(new APIConnectionGroupWrapper(connectionGroup)); // Return the new connection group identifier @@ -440,7 +440,7 @@ public class ConnectionGroupRESTService { // Get the connection group directory ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); - Directory connectionGroupDirectory = + Directory connectionGroupDirectory = rootGroup.getConnectionGroupDirectory(); // Retrieve connection group to update diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/permission/APIPermissionSet.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/permission/APIPermissionSet.java index 1d4a14774..697641086 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/permission/APIPermissionSet.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/permission/APIPermissionSet.java @@ -114,10 +114,10 @@ public class APIPermissionSet { * ObjectPermissionSet. */ private void addObjectPermissions(Map> permissions, - ObjectPermissionSet permSet) throws GuacamoleException { + ObjectPermissionSet permSet) throws GuacamoleException { // Add all provided object permissions - for (ObjectPermission permission : permSet.getPermissions()) { + for (ObjectPermission permission : permSet.getPermissions()) { // Get associated set of permissions String identifier = permission.getObjectIdentifier(); diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/APIUser.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/APIUser.java index 2efcb6992..6351f2942 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/APIUser.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/APIUser.java @@ -55,7 +55,7 @@ public class APIUser { * @param user The User to construct the APIUser from. */ public APIUser(User user) { - this.username = user.getUsername(); + this.username = user.getIdentifier(); this.password = user.getPassword(); } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/APIUserWrapper.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/APIUserWrapper.java index d6032bbd2..52e5e707d 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/APIUserWrapper.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/APIUserWrapper.java @@ -52,12 +52,12 @@ public class APIUserWrapper implements User { } @Override - public String getUsername() { + public String getIdentifier() { return apiUser.getUsername(); } @Override - public void setUsername(String username) { + public void setIdentifier(String username) { apiUser.setUsername(username); } @@ -78,19 +78,19 @@ public class APIUserWrapper implements User { } @Override - public ObjectPermissionSet getConnectionPermissions() + public ObjectPermissionSet getConnectionPermissions() throws GuacamoleException { throw new GuacamoleUnsupportedException("APIUserWrapper does not provide permission access."); } @Override - public ObjectPermissionSet getConnectionGroupPermissions() + public ObjectPermissionSet getConnectionGroupPermissions() throws GuacamoleException { throw new GuacamoleUnsupportedException("APIUserWrapper does not provide permission access."); } @Override - public ObjectPermissionSet getUserPermissions() + public ObjectPermissionSet getUserPermissions() throws GuacamoleException { throw new GuacamoleUnsupportedException("APIUserWrapper does not provide permission access."); } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java index b9345ce45..d8fc5f15a 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java @@ -151,12 +151,12 @@ public class UserRESTService { boolean isAdmin = systemPermissions.hasPermission(SystemPermission.Type.ADMINISTER); // Get the directory - Directory userDirectory = userContext.getUserDirectory(); + Directory userDirectory = userContext.getUserDirectory(); // Filter users, if requested Collection userIdentifiers = userDirectory.getIdentifiers(); if (!isAdmin && permissions != null) { - ObjectPermissionSet userPermissions = self.getUserPermissions(); + ObjectPermissionSet userPermissions = self.getUserPermissions(); userIdentifiers = userPermissions.getAccessibleObjects(permissions, userIdentifiers); } @@ -217,7 +217,7 @@ public class UserRESTService { UserContext userContext = authenticationService.getUserContext(authToken); // Get the directory - Directory userDirectory = userContext.getUserDirectory(); + Directory userDirectory = userContext.getUserDirectory(); // Randomly set the password if it wasn't provided if (user.getPassword() == null) @@ -256,7 +256,7 @@ public class UserRESTService { UserContext userContext = authenticationService.getUserContext(authToken); // Get the directory - Directory userDirectory = userContext.getUserDirectory(); + Directory userDirectory = userContext.getUserDirectory(); // Validate data and path are sane if (!user.getUsername().equals(username)) @@ -298,7 +298,7 @@ public class UserRESTService { UserContext userContext = authenticationService.getUserContext(authToken); // Get the directory - Directory userDirectory = userContext.getUserDirectory(); + Directory userDirectory = userContext.getUserDirectory(); // Get the user User existingUser = userDirectory.get(username); @@ -338,7 +338,7 @@ public class UserRESTService { User user; // If username is own username, just use self - might not have query permissions - if (userContext.self().getUsername().equals(username)) + if (userContext.self().getIdentifier().equals(username)) user = userContext.self(); // If not self, query corresponding user from directory @@ -430,10 +430,10 @@ public class UserRESTService { throw new GuacamoleResourceNotFoundException("No such user: \"" + username + "\""); // Permission patches for all types of permissions - PermissionSetPatch> connectionPermissionPatch = new PermissionSetPatch>(); - PermissionSetPatch> connectionGroupPermissionPatch = new PermissionSetPatch>(); - PermissionSetPatch> userPermissionPatch = new PermissionSetPatch>(); - PermissionSetPatch systemPermissionPatch = new PermissionSetPatch(); + PermissionSetPatch connectionPermissionPatch = new PermissionSetPatch(); + PermissionSetPatch connectionGroupPermissionPatch = new PermissionSetPatch(); + PermissionSetPatch userPermissionPatch = new PermissionSetPatch(); + PermissionSetPatch systemPermissionPatch = new PermissionSetPatch(); // Apply all patch operations individually for (APIPatch patch : patches) { @@ -448,7 +448,7 @@ public class UserRESTService { ObjectPermission.Type type = ObjectPermission.Type.valueOf(patch.getValue()); // Create and update corresponding permission - ObjectPermission permission = new ObjectPermission(type, identifier); + ObjectPermission permission = new ObjectPermission(type, identifier); updatePermissionSet(patch.getOp(), connectionPermissionPatch, permission); } @@ -461,7 +461,7 @@ public class UserRESTService { ObjectPermission.Type type = ObjectPermission.Type.valueOf(patch.getValue()); // Create and update corresponding permission - ObjectPermission permission = new ObjectPermission(type, identifier); + ObjectPermission permission = new ObjectPermission(type, identifier); updatePermissionSet(patch.getOp(), connectionGroupPermissionPatch, permission); } @@ -474,7 +474,7 @@ public class UserRESTService { ObjectPermission.Type type = ObjectPermission.Type.valueOf(patch.getValue()); // Create and update corresponding permission - ObjectPermission permission = new ObjectPermission(type, identifier); + ObjectPermission permission = new ObjectPermission(type, identifier); updatePermissionSet(patch.getOp(), userPermissionPatch, permission); } From bf8957986e39bdbabd9ac7aa04f15a8df8dbf3c6 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 21 Feb 2015 22:05:27 -0800 Subject: [PATCH 14/19] GUAC-1100: Remove old recursive tree query. Add stub of new batching tree object. --- .../ConnectionGroupRESTService.java | 203 +----------------- .../connectiongroup/ConnectionGroupTree.java | 84 ++++++++ 2 files changed, 91 insertions(+), 196 deletions(-) create mode 100644 guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupTree.java diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java index 22430bf84..cab7a3550 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java @@ -23,9 +23,6 @@ package org.glyptodon.guacamole.net.basic.rest.connectiongroup; import com.google.inject.Inject; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; import java.util.List; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; @@ -39,20 +36,13 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import org.glyptodon.guacamole.GuacamoleClientException; import org.glyptodon.guacamole.GuacamoleException; -import org.glyptodon.guacamole.GuacamoleResourceNotFoundException; -import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionGroup; import org.glyptodon.guacamole.net.auth.Directory; -import org.glyptodon.guacamole.net.auth.User; import org.glyptodon.guacamole.net.auth.UserContext; import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; -import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet; -import org.glyptodon.guacamole.net.auth.permission.SystemPermission; -import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet; import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure; import org.glyptodon.guacamole.net.basic.rest.ObjectRetrievalService; import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService; -import org.glyptodon.guacamole.net.basic.rest.connection.APIConnection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -83,177 +73,6 @@ public class ConnectionGroupRESTService { @Inject private ObjectRetrievalService retrievalService; - /** - * Determines whether the given user has at least one of the given - * permissions for the connection having the given identifier. - * - * @param user - * The user to check permissions for. - * - * @param identifier - * The identifier of the connection to check permissions for. - * - * @param permissions - * The permissions to check. The given user must have one or more of - * these permissions for this function to return true. - * - * @return - * true if the user has at least one of the given permissions. - */ - private boolean hasConnectionPermission(User user, String identifier, - List permissions) throws GuacamoleException { - - // Retrieve connection permissions - ObjectPermissionSet connectionPermissions = user.getConnectionPermissions(); - - // Determine whether user has at least one of the given permissions - for (ObjectPermission.Type permission : permissions) { - if (connectionPermissions.hasPermission(permission, identifier)) - return true; - } - - // None of the given permissions were present - return false; - - } - - /** - * Determines whether the given user has at least one of the given - * permissions for the connection group having the given identifier. - * - * @param user - * The user to check permissions for. - * - * @param identifier - * The identifier of the connection group to check permissions for. - * - * @param permissions - * The permissions to check. The given user must have one or more of - * these permissions for this function to return true. - * - * @return - * true if the user has at least one of the given permissions. - */ - private boolean hasConnectionGroupPermission(User user, String identifier, - List permissions) throws GuacamoleException { - - // Retrieve connection group permissions - ObjectPermissionSet connectionGroupPermissions = user.getConnectionGroupPermissions(); - - // Determine whether user has at least one of the given permissions - for (ObjectPermission.Type permission : permissions) { - if (connectionGroupPermissions.hasPermission(permission, identifier)) - return true; - } - - // None of the given permissions were present - return false; - - } - - /** - * Retrieves the given connection group from the user context, including - * all descendant connections and groups if requested. - * - * @param userContext - * The user context from which to retrieve the connection group. - * - * @param identifier - * The unique identifier of the connection group to retrieve. - * - * @param includeDescendants - * Whether the descendant connections and groups of the given - * connection group should also be retrieved. - * - * @param permissions - * The set of permissions to filter with. A user must have one or more - * of these permissions for a connection to appear in the result. - * If null, no filtering will be performed. - * - * @return - * The requested connection group, or null if no such connection group - * exists. - * - * @throws GuacamoleException - * If an error occurs while retrieving the requested connection group - * or any of its descendants. - */ - private APIConnectionGroup retrieveConnectionGroup(UserContext userContext, - String identifier, boolean includeDescendants, List permissions) - throws GuacamoleException { - - User self = userContext.self(); - - // An admin user has access to any connection or connection group - SystemPermissionSet systemPermissions = self.getSystemPermissions(); - boolean isAdmin = systemPermissions.hasPermission(SystemPermission.Type.ADMINISTER); - - // Retrieve specified connection group - ConnectionGroup connectionGroup; - try { - connectionGroup = retrievalService.retrieveConnectionGroup(userContext, identifier); - } - catch (GuacamoleResourceNotFoundException e) { - return null; - } - - // Wrap queried connection group - APIConnectionGroup apiConnectionGroup = new APIConnectionGroup(connectionGroup); - - // Recursively query all descendants if necessary, only querying the - // descendants of balancing groups if we have admin permission on that - // group - if (includeDescendants - && (connectionGroup.getType() != ConnectionGroup.Type.BALANCING - || isAdmin - || hasConnectionGroupPermission(self, identifier, - Collections.singletonList(ObjectPermission.Type.ADMINISTER)))) { - - // Query all child connections - Collection apiConnections = new ArrayList(); - Directory connectionDirectory = connectionGroup.getConnectionDirectory(); - - for (String childIdentifier : connectionDirectory.getIdentifiers()) { - - // Pull current connection - silently ignore if connection was removed prior to read - Connection childConnection = connectionDirectory.get(childIdentifier); - if (childConnection == null) - continue; - - // Filter based on permission, if requested - if (isAdmin || permissions == null || hasConnectionPermission(self, childIdentifier, permissions)) - apiConnections.add(new APIConnection(childConnection)); - - } - - // Associate child connections with current connection group - apiConnectionGroup.setChildConnections(apiConnections); - - // Query all child connection groups - Collection apiConnectionGroups = new ArrayList(); - Directory groupDirectory = connectionGroup.getConnectionGroupDirectory(); - - for (String childIdentifier : groupDirectory.getIdentifiers()) { - - // Pull current connection group - silently ignore if connection group was removed prior to read - APIConnectionGroup childConnectionGroup = retrieveConnectionGroup(userContext, childIdentifier, true, permissions); - if (childConnectionGroup == null) - continue; - - apiConnectionGroups.add(childConnectionGroup); - - } - - // Associate child groups with current connection group - apiConnectionGroup.setChildConnectionGroups(apiConnectionGroups); - - } - - // Return the connectiion group - return apiConnectionGroup; - - } - /** * Gets an individual connection group. * @@ -278,12 +97,8 @@ public class ConnectionGroupRESTService { UserContext userContext = authenticationService.getUserContext(authToken); - // Retrieve requested connection group only - APIConnectionGroup connectionGroup = retrieveConnectionGroup(userContext, connectionGroupID, false, null); - if (connectionGroup == null) - throw new GuacamoleResourceNotFoundException("No such connection group: \"" + connectionGroupID + "\""); - - return connectionGroup; + // Retrieve the requested connection group + return new APIConnectionGroup(retrievalService.retrieveConnectionGroup(userContext, connectionGroupID)); } @@ -320,16 +135,12 @@ public class ConnectionGroupRESTService { UserContext userContext = authenticationService.getUserContext(authToken); - // Do not filter on permissions if no permissions are specified - if (permissions != null && permissions.isEmpty()) - permissions = null; - - // Retrieve requested connection group and all descendants - APIConnectionGroup connectionGroup = retrieveConnectionGroup(userContext, connectionGroupID, true, permissions); - if (connectionGroup == null) - throw new GuacamoleResourceNotFoundException("No such connection group: \"" + connectionGroupID + "\""); + // Retrieve the requested tree, filtering by the given permissions + ConnectionGroup treeRoot = retrievalService.retrieveConnectionGroup(userContext, connectionGroupID); + ConnectionGroupTree tree = new ConnectionGroupTree(treeRoot, permissions); - return connectionGroup; + // Return tree as a connection group + return tree.getRootAPIConnectionGroup(); } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupTree.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupTree.java new file mode 100644 index 000000000..9851710cf --- /dev/null +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupTree.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.net.basic.rest.connectiongroup; + +import java.util.List; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.net.auth.ConnectionGroup; +import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; + +/** + * Provides access to the entire tree of connection groups and their + * connections. + * + * @author Michael Jumper + */ +public class ConnectionGroupTree { + + /** + * The root connection group. + */ + private final APIConnectionGroup root; + + /** + * Creates a new connection group tree using the given connection group as + * the tree root. + * + * @param root + * The connection group to use as the root of this connection group + * tree. + * + * @param permissions + * If specified and non-empty, limit the contents of the tree to only + * those connections for which the current user has any of the given + * permissions. Otherwise, all visible connections are returned. + * Connection groups are unaffected by this parameter. + * + * @throws GuacamoleException + * If an error occurs while retrieving the tree of connection groups + * and their descendants. + */ + public ConnectionGroupTree(ConnectionGroup root, + List permissions) throws GuacamoleException { + + // Store root of tree + this.root = new APIConnectionGroup(root); + + // STUB + + } + + /** + * Returns the entire connection group tree as an APIConnectionGroup. The + * returned APIConnectionGroup is the root group and will contain all + * descendant connection groups and connections, arranged hierarchically. + * + * @return + * The root connection group, containing the entire connection group + * tree and all connections. + */ + public APIConnectionGroup getRootAPIConnectionGroup() { + return root; + } + +} From e9cebd181b914cb94386d10d48cd802646ac4f58 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 21 Feb 2015 23:41:22 -0800 Subject: [PATCH 15/19] GUAC-1100: Implement recursive BFS tree retrieval. --- .../connectiongroup/ConnectionGroupTree.java | 164 +++++++++++++++++- 1 file changed, 160 insertions(+), 4 deletions(-) diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupTree.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupTree.java index 9851710cf..f20bea7a1 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupTree.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupTree.java @@ -22,10 +22,19 @@ package org.glyptodon.guacamole.net.basic.rest.connectiongroup; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionGroup; import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; +import org.glyptodon.guacamole.net.basic.rest.connection.APIConnection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Provides access to the entire tree of connection groups and their @@ -35,11 +44,155 @@ import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; */ public class ConnectionGroupTree { + /** + * Logger for this class. + */ + private static final Logger logger = LoggerFactory.getLogger(ConnectionGroupTree.class); + /** * The root connection group. */ - private final APIConnectionGroup root; + private final ConnectionGroup root; + + /** + * The root connection group as an APIConnectionGroup. + */ + private final APIConnectionGroup rootAPIGroup; + /** + * All connection groups that have been retrieved, stored by their + * identifiers. + */ + private final Map retrievedGroups = + new HashMap(); + + /** + * Adds each of the provided connections to the current tree as children + * of their respective parents. The parent connection groups must already + * be added. + * + * @param connections + * The connections to add to the tree. + * + * @throws GuacamoleException + * If an error occurs while adding the connection to the tree. + */ + private void addConnections(Collection connections) + throws GuacamoleException { + + // Add each connection to the tree + for (Connection connection : connections) { + + // Retrieve the connection's parent group + APIConnectionGroup parent = retrievedGroups.get(connection.getParentIdentifier()); + if (parent != null) { + + Collection children = parent.getChildConnections(); + + // Create child collection if it does not yet exist + if (children == null) { + children = new ArrayList(); + parent.setChildConnections(children); + } + + // Add child + children.add(new APIConnection(connection)); + + } + + // Warn of internal consistency issues + else + logger.debug("Connection \"{}\" cannot be added to the tree: parent \"{}\" does not actually exist.", + connection.getIdentifier(), + connection.getParentIdentifier()); + + } // end for each connection + + } + + /** + * Adds each of the provided connection groups to the current tree as + * children of their respective parents. The parent connection groups must + * already be added. + * + * @param connectionGroups + * The connection groups to add to the tree. + */ + private void addConnectionGroups(Collection connectionGroups) { + + // Add each connection group to the tree + for (ConnectionGroup connectionGroup : connectionGroups) { + + // Retrieve the connection group's parent group + APIConnectionGroup parent = retrievedGroups.get(connectionGroup.getParentIdentifier()); + if (parent != null) { + + Collection children = parent.getChildConnectionGroups(); + + // Create child collection if it does not yet exist + if (children == null) { + children = new ArrayList(); + parent.setChildConnectionGroups(children); + } + + // Add child + APIConnectionGroup apiConnectionGroup = new APIConnectionGroup(connectionGroup); + retrievedGroups.put(connectionGroup.getIdentifier(), apiConnectionGroup); + children.add(apiConnectionGroup); + + } + + // Warn of internal consistency issues + else + logger.debug("Connection group \"{}\" cannot be added to the tree: parent \"{}\" does not actually exist.", + connectionGroup.getIdentifier(), + connectionGroup.getParentIdentifier()); + + } // end for each connection group + + } + + /** + * Adds all descendants of the given parent groups to their corresponding + * parents already stored under root. + * + * @param parents + * The parents whose descendants should be added to the tree. + * + * @throws GuacamoleException + * If an error occurs while retrieving the descendants. + */ + private void addDescendants(Collection parents) + throws GuacamoleException { + + // If no parents, nothing to do + if (parents.isEmpty()) + return; + + Collection childConnectionIdentifiers = new ArrayList(); + Collection childConnectionGroupIdentifiers = new ArrayList(); + + // Build lists of identifiers for retrieval + for (ConnectionGroup parent : parents) { + childConnectionIdentifiers.addAll(parent.getConnectionDirectory().getIdentifiers()); + childConnectionGroupIdentifiers.addAll(parent.getConnectionGroupDirectory().getIdentifiers()); + } + + // Retrieve child connections + if (!childConnectionIdentifiers.isEmpty()) { + Collection childConnections = root.getConnectionDirectory().getAll(childConnectionIdentifiers); + addConnections(childConnections); + } + + // Retrieve child connection groups + if (!childConnectionGroupIdentifiers.isEmpty()) { + Collection childConnectionGroups = root.getConnectionGroupDirectory().getAll(childConnectionGroupIdentifiers); + addConnectionGroups(childConnectionGroups); + addDescendants(childConnectionGroups); + } + + } + /** * Creates a new connection group tree using the given connection group as * the tree root. @@ -62,9 +215,12 @@ public class ConnectionGroupTree { List permissions) throws GuacamoleException { // Store root of tree - this.root = new APIConnectionGroup(root); + this.root = root; + this.rootAPIGroup = new APIConnectionGroup(root); + retrievedGroups.put(root.getIdentifier(), this.rootAPIGroup); - // STUB + // Add all descendants + addDescendants(Collections.singleton(root)); } @@ -78,7 +234,7 @@ public class ConnectionGroupTree { * tree and all connections. */ public APIConnectionGroup getRootAPIConnectionGroup() { - return root; + return rootAPIGroup; } } From 220e33eca1aab92a84a42eaaad3e6619a7b025de Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 21 Feb 2015 23:42:22 -0800 Subject: [PATCH 16/19] GUAC-1100: Keep parent identifiers within SimpleUserContext consistent with reality. --- .../simple/SimpleConnectionDirectory.java | 26 ++++++++--------- .../net/auth/simple/SimpleUserContext.java | 28 +++++++++++++++++-- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionDirectory.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionDirectory.java index a8641cb6c..50e9d4ff5 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionDirectory.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionDirectory.java @@ -22,11 +22,10 @@ package org.glyptodon.guacamole.net.auth.simple; +import java.util.Collection; import java.util.HashMap; import java.util.Map; -import java.util.Map.Entry; import org.glyptodon.guacamole.net.auth.Connection; -import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; /** * An extremely simple read-only implementation of a Directory of @@ -44,22 +43,21 @@ public class SimpleConnectionDirectory extends SimpleDirectory { new HashMap(); /** - * Creates a new SimpleConnectionDirectory which provides - * access to the configurations contained within the given Map. + * Creates a new SimpleConnectionDirectory which provides access to the + * connections contained within the given Map. * - * @param configs The Map of GuacamoleConfigurations to provide access to. + * @param connections + * A Collection of all connections that should be present in this + * connection directory. */ - public SimpleConnectionDirectory( - Map configs) { + public SimpleConnectionDirectory(Collection connections) { - // Create connections for each config - for (Entry entry : configs.entrySet()) - connections.put(entry.getKey(), - new SimpleConnection(entry.getKey(), entry.getKey(), - entry.getValue())); + // Add all given connections + for (Connection connection : connections) + this.connections.put(connection.getIdentifier(), connection); - // Use the connection map to back the underlying AbstractDirectory - super.setObjects(connections); + // Use the connection map to back the underlying directory + super.setObjects(this.connections); } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java index 474bc5373..032fc0dd4 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java @@ -22,10 +22,13 @@ package org.glyptodon.guacamole.net.auth.simple; +import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.UUID; import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionGroup; import org.glyptodon.guacamole.net.auth.Directory; import org.glyptodon.guacamole.net.auth.User; @@ -41,6 +44,11 @@ import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; */ public class SimpleUserContext implements UserContext { + /** + * The unique identifier of the root connection group. + */ + private static final String ROOT_IDENTIFIER = "ROOT"; + /** * Reference to the user whose permissions dictate the configurations * accessible within this UserContext. @@ -82,9 +90,25 @@ public class SimpleUserContext implements UserContext { */ public SimpleUserContext(String username, Map configs) { + // Produce collection of connections from given configs + Collection connections = new ArrayList(configs.size()); + for (Map.Entry configEntry : configs.entrySet()) { + + // Get connection identifier and configuration + String identifier = configEntry.getKey(); + GuacamoleConfiguration config = configEntry.getValue(); + + // Add as simple connection + Connection connection = new SimpleConnection(identifier, identifier, config); + connection.setParentIdentifier(ROOT_IDENTIFIER); + connections.add(connection); + + } + // Add root group that contains only configurations - this.connectionGroup = new SimpleConnectionGroup("ROOT", "ROOT", - new SimpleConnectionDirectory(configs), + this.connectionGroup = new SimpleConnectionGroup( + ROOT_IDENTIFIER, ROOT_IDENTIFIER, + new SimpleConnectionDirectory(connections), new SimpleConnectionGroupDirectory(Collections.EMPTY_LIST)); // Build new user from credentials, giving the user an arbitrary name From 6f61300cbc59c75e67a8ccf3b9e9de01471eda2e Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 23 Feb 2015 12:42:47 -0800 Subject: [PATCH 17/19] GUAC-1100: Move connection and connection group directories to root level only. --- .../guacamole/net/auth/Connectable.java | 54 +++++++++++++ .../guacamole/net/auth/Connection.java | 19 +---- .../guacamole/net/auth/ConnectionGroup.java | 53 ++++--------- .../guacamole/net/auth/Directory.java | 12 --- .../guacamole/net/auth/UserContext.java | 28 +++++++ .../auth/simple/SimpleConnectionGroup.java | 62 +++++++-------- .../net/auth/simple/SimpleDirectory.java | 6 -- .../guacamole/net/auth/simple/SimpleUser.java | 75 ++++++++++--------- .../net/auth/simple/SimpleUserContext.java | 57 ++++++++++---- .../net/basic/TunnelRequestService.java | 12 +-- .../basic/rest/ObjectRetrievalService.java | 13 ++-- .../connection/ConnectionRESTService.java | 23 +----- .../APIConnectionGroupWrapper.java | 5 +- .../ConnectionGroupRESTService.java | 25 +------ .../connectiongroup/ConnectionGroupTree.java | 23 +++--- 15 files changed, 246 insertions(+), 221 deletions(-) create mode 100644 guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connectable.java diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connectable.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connectable.java new file mode 100644 index 000000000..6ce62c916 --- /dev/null +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connectable.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2013 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.net.auth; + +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.net.GuacamoleSocket; +import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; + +/** + * An object which Guacamole can connect to. + * + * @author Michael Jumper + */ +public interface Connectable { + + /** + * Establishes a connection to guacd using the information associated with + * this object. The connection will be provided the given client + * information. + * + * @param info + * Information associated with the connecting client. + * + * @return + * A fully-established GuacamoleSocket. + * + * @throws GuacamoleException + * If an error occurs while connecting to guacd, or if permission to + * connect is denied. + */ + public GuacamoleSocket connect(GuacamoleClientInformation info) + throws GuacamoleException; + +} diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connection.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connection.java index 63e60a328..6fac0809f 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connection.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connection.java @@ -24,8 +24,6 @@ package org.glyptodon.guacamole.net.auth; import java.util.List; import org.glyptodon.guacamole.GuacamoleException; -import org.glyptodon.guacamole.net.GuacamoleSocket; -import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; /** @@ -36,7 +34,7 @@ import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; * * @author Michael Jumper */ -public interface Connection extends Identifiable { +public interface Connection extends Identifiable, Connectable { /** * Returns the name assigned to this Connection. @@ -86,21 +84,6 @@ public interface Connection extends Identifiable { */ public void setConfiguration(GuacamoleConfiguration config); - /** - * Establishes a connection to guacd using the GuacamoleConfiguration - * associated with this Connection, and returns the resulting, connected - * GuacamoleSocket. The GuacamoleSocket will be pre-configured and will - * already have passed the handshake stage. - * - * @param info Information associated with the connecting client. - * @return A fully-established GuacamoleSocket. - * - * @throws GuacamoleException If an error occurs while connecting to guacd, - * or if permission to connect is denied. - */ - public GuacamoleSocket connect(GuacamoleClientInformation info) - throws GuacamoleException; - /** * Returns a list of ConnectionRecords representing the usage history * of this Connection, including any active users. ConnectionRecords diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionGroup.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionGroup.java index a99978759..21a1e8de6 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionGroup.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionGroup.java @@ -22,9 +22,7 @@ package org.glyptodon.guacamole.net.auth; -import org.glyptodon.guacamole.GuacamoleException; -import org.glyptodon.guacamole.net.GuacamoleSocket; -import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; +import java.util.Set; /** * Represents a connection group, which can contain both other connection groups @@ -32,7 +30,7 @@ import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; * * @author James Muehlner */ -public interface ConnectionGroup extends Identifiable { +public interface ConnectionGroup extends Identifiable, Connectable { /** * All legal types of connection group. @@ -102,45 +100,24 @@ public interface ConnectionGroup extends Identifiable { public Type getType(); /** - * Retrieves a Directory which can be used to view and manipulate - * connections and their configurations, but only as allowed by the - * permissions given to the user. + * Returns the identifiers of all readable connections that are children + * of this connection group. * - * @return A Directory whose operations are bound by the permissions of - * the user. - * - * @throws GuacamoleException If an error occurs while creating the - * Directory. + * @return + * The set of identifiers of all readable connections that are children + * of this connection group. */ - Directory getConnectionDirectory() - throws GuacamoleException; + public Set getConnectionIdentifiers(); /** - * Retrieves a Directory which can be used to view and manipulate - * connection groups and their members, but only as allowed by the - * permissions given to the user. + * Returns the identifiers of all readable connection groups that are + * children of this connection group. * - * @return A Directory whose operations are bound by the permissions of - * the user. - * - * @throws GuacamoleException If an error occurs while creating the - * Directory. + * @return + * The set of identifiers of all readable connection groups that are + * children of this connection group. */ - Directory getConnectionGroupDirectory() - throws GuacamoleException; + + public Set getConnectionGroupIdentifiers(); - /** - * Establishes a connection to guacd using a connection chosen from among - * the connections in this ConnectionGroup, and returns the resulting, - * connected GuacamoleSocket. - * - * @param info Information associated with the connecting client. - * @return A fully-established GuacamoleSocket. - * - * @throws GuacamoleException If an error occurs while connecting to guacd, - * or if permission to connect is denied. - */ - public GuacamoleSocket connect(GuacamoleClientInformation info) - throws GuacamoleException; - } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Directory.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Directory.java index b241c017e..4dbb60ce9 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Directory.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Directory.java @@ -122,16 +122,4 @@ public interface Directory { */ void remove(String identifier) throws GuacamoleException; - /** - * Moves the object with the given identifier to the given directory. - * - * @param identifier The identifier of the object to remove. - * @param directory The directory to move the object to. - * - * @throws GuacamoleException If an error occurs while moving the object, - * or if moving object is not allowed. - */ - void move(String identifier, Directory directory) - throws GuacamoleException; - } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/UserContext.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/UserContext.java index deba2cb7d..c38d9a90f 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/UserContext.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/UserContext.java @@ -54,6 +54,34 @@ public interface UserContext { */ Directory getUserDirectory() throws GuacamoleException; + /** + * Retrieves a Directory which can be used to view and manipulate + * connections and their configurations, but only as allowed by the + * permissions given to the user. + * + * @return A Directory whose operations are bound by the permissions of + * the user. + * + * @throws GuacamoleException If an error occurs while creating the + * Directory. + */ + Directory getConnectionDirectory() + throws GuacamoleException; + + /** + * Retrieves a Directory which can be used to view and manipulate + * connection groups and their members, but only as allowed by the + * permissions given to the user. + * + * @return A Directory whose operations are bound by the permissions of + * the user. + * + * @throws GuacamoleException If an error occurs while creating the + * Directory. + */ + Directory getConnectionGroupDirectory() + throws GuacamoleException; + /** * Retrieves a connection group which can be used to view and manipulate * connections, but only as allowed by the permissions given to the user of diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroup.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroup.java index 6f4cb1051..eb197d01a 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroup.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroup.java @@ -22,18 +22,19 @@ package org.glyptodon.guacamole.net.auth.simple; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleSecurityException; import org.glyptodon.guacamole.net.GuacamoleSocket; import org.glyptodon.guacamole.net.auth.AbstractConnectionGroup; -import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionGroup; -import org.glyptodon.guacamole.net.auth.Directory; import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; /** * An extremely simple read-only implementation of a ConnectionGroup which - * returns the connection and connection group directories it was constructed + * returns the connection and connection group identifiers it was constructed * with. Load balancing across this connection group is not allowed. * * @author James Muehlner @@ -41,31 +42,34 @@ import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; public class SimpleConnectionGroup extends AbstractConnectionGroup { /** - * Underlying connection directory, containing all connections within this - * group. + * The identifiers of all connections in this group. */ - private final Directory connectionDirectory; + private final Set connectionIdentifiers; /** - * Underlying connection group directory, containing all connections within - * this group. + * The identifiers of all connection groups in this group. */ - private final Directory connectionGroupDirectory; + private final Set connectionGroupIdentifiers; /** * Creates a new SimpleConnectionGroup having the given name and identifier - * which will expose the given directories as its contents. + * which will expose the given contents. * - * @param name The name to associate with this connection. - * @param identifier The identifier to associate with this connection. - * @param connectionDirectory The connection directory to expose when - * requested. - * @param connectionGroupDirectory The connection group directory to expose - * when requested. + * @param name + * The name to associate with this connection group. + * + * @param identifier + * The identifier to associate with this connection group. + * + * @param connectionIdentifiers + * The connection identifiers to expose when requested. + * + * @param connectionGroupIdentifiers + * The connection group identifiers to expose when requested. */ public SimpleConnectionGroup(String name, String identifier, - Directory connectionDirectory, - Directory connectionGroupDirectory) { + Collection connectionIdentifiers, + Collection connectionGroupIdentifiers) { // Set name setName(name); @@ -76,22 +80,20 @@ public class SimpleConnectionGroup extends AbstractConnectionGroup { // Set group type setType(ConnectionGroup.Type.ORGANIZATIONAL); - // Assign directories - this.connectionDirectory = connectionDirectory; - this.connectionGroupDirectory = connectionGroupDirectory; + // Populate contents + this.connectionIdentifiers = new HashSet(connectionIdentifiers); + this.connectionGroupIdentifiers = new HashSet(connectionGroupIdentifiers); } - - @Override - public Directory getConnectionDirectory() - throws GuacamoleException { - return connectionDirectory; - } @Override - public Directory getConnectionGroupDirectory() - throws GuacamoleException { - return connectionGroupDirectory; + public Set getConnectionIdentifiers() { + return connectionIdentifiers; + } + + @Override + public Set getConnectionGroupIdentifiers() { + return connectionGroupIdentifiers; } @Override diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleDirectory.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleDirectory.java index 570fe2bcd..caee07e2a 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleDirectory.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleDirectory.java @@ -138,10 +138,4 @@ public class SimpleDirectory implements Directory { throw new GuacamoleSecurityException("Permission denied."); } - @Override - public void move(String identifier, Directory directory) - throws GuacamoleException { - throw new GuacamoleSecurityException("Permission denied."); - } - } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java index 873c59062..fa0899fa2 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java @@ -24,15 +24,12 @@ package org.glyptodon.guacamole.net.auth.simple; import java.util.Collection; import java.util.HashSet; -import java.util.Map; import java.util.Set; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.net.auth.AbstractUser; -import org.glyptodon.guacamole.net.auth.ConnectionGroup; import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet; import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet; -import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; /** * An extremely basic User implementation. @@ -60,46 +57,52 @@ public class SimpleUser extends AbstractUser { } /** - * Creates a new SimpleUser having the given username. + * Adds a new READ permission to the given set of permissions for each of + * the given identifiers. * - * @param username The username to assign to this SimpleUser. - * @param configs All configurations this user has read access to. - * @param groups All groups this user has read access to. + * @param permissions + * The set of permissions to add READ permissions to. + * + * @param identifiers + * The identifiers which should each have a corresponding READ + * permission added to the given set. + */ + private void addReadPermissions(Set permissions, + Collection identifiers) { + + // Add a READ permission to the set for each identifier given + for (String identifier : identifiers) { + permissions.add(new ObjectPermission ( + ObjectPermission.Type.READ, + identifier + )); + } + + } + + /** + * Creates a new SimpleUser having the given username and READ access to + * the connections and groups having the given identifiers. + * + * @param username + * The username to assign to this SimpleUser. + * @param connectionIdentifiers + * The identifiers of all connections this user has READ access to. + * + * @param connectionGroupIdentifiers + * The identifiers of all connection groups this user has READ access + * to. */ public SimpleUser(String username, - Map configs, - Collection groups) { + Collection connectionIdentifiers, + Collection connectionGroupIdentifiers) { // Set username setIdentifier(username); - // Add connection permissions - for (String identifier : configs.keySet()) { - - // Create permission - ObjectPermission permission = new ObjectPermission( - ObjectPermission.Type.READ, - identifier - ); - - // Add to set - connectionPermissions.add(permission); - - } - - // Add group permissions - for (ConnectionGroup group : groups) { - - // Create permission - ObjectPermission permission = new ObjectPermission( - ObjectPermission.Type.READ, - group.getIdentifier() - ); - - // Add to set - connectionGroupPermissions.add(permission); - - } + // Add permissions + addReadPermissions(connectionPermissions, connectionIdentifiers); + addReadPermissions(connectionGroupPermissions, connectionGroupIdentifiers); } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java index 032fc0dd4..8ee7e84c1 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java @@ -62,10 +62,21 @@ public class SimpleUserContext implements UserContext { private final Directory userDirectory; /** - * The ConnectionGroup with access only to those Connections that the User - * associated with this UserContext has access to. + * The Directory with access only to the root group associated with this + * UserContext. */ - private final ConnectionGroup connectionGroup; + private final Directory connectionGroupDirectory; + + /** + * The Directory with access to all connections within the root group + * associated with this UserContext. + */ + private final Directory connectionDirectory; + + /** + * The root connection group. + */ + private final ConnectionGroup rootGroup; /** * Creates a new SimpleUserContext which provides access to only those @@ -90,6 +101,9 @@ public class SimpleUserContext implements UserContext { */ public SimpleUserContext(String username, Map configs) { + Collection connectionIdentifiers = new ArrayList(configs.size()); + Collection connectionGroupIdentifiers = Collections.singleton(ROOT_IDENTIFIER); + // Produce collection of connections from given configs Collection connections = new ArrayList(configs.size()); for (Map.Entry configEntry : configs.entrySet()) { @@ -103,20 +117,25 @@ public class SimpleUserContext implements UserContext { connection.setParentIdentifier(ROOT_IDENTIFIER); connections.add(connection); + // Add identifier to overall set of identifiers + connectionIdentifiers.add(identifier); + } - // Add root group that contains only configurations - this.connectionGroup = new SimpleConnectionGroup( - ROOT_IDENTIFIER, ROOT_IDENTIFIER, - new SimpleConnectionDirectory(connections), - new SimpleConnectionGroupDirectory(Collections.EMPTY_LIST)); + // Add root group that contains only the given configurations + this.rootGroup = new SimpleConnectionGroup( + ROOT_IDENTIFIER, ROOT_IDENTIFIER, + connectionIdentifiers, Collections.EMPTY_LIST + ); - // Build new user from credentials, giving the user an arbitrary name - this.self = new SimpleUser(username, - configs, Collections.singleton(connectionGroup)); + // Build new user from credentials + this.self = new SimpleUser(username, connectionIdentifiers, + connectionGroupIdentifiers); - // Create user directory for new user + // Create directories for new user this.userDirectory = new SimpleUserDirectory(self); + this.connectionDirectory = new SimpleConnectionDirectory(connections); + this.connectionGroupDirectory = new SimpleConnectionGroupDirectory(Collections.singleton(this.rootGroup)); } @@ -131,9 +150,21 @@ public class SimpleUserContext implements UserContext { return userDirectory; } + @Override + public Directory getConnectionDirectory() + throws GuacamoleException { + return connectionDirectory; + } + + @Override + public Directory getConnectionGroupDirectory() + throws GuacamoleException { + return connectionGroupDirectory; + } + @Override public ConnectionGroup getRootConnectionGroup() throws GuacamoleException { - return connectionGroup; + return rootGroup; } } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/TunnelRequestService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/TunnelRequestService.java index 8c1679236..b0ba6ee39 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/TunnelRequestService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/TunnelRequestService.java @@ -210,11 +210,9 @@ public class TunnelRequestService { // Connection identifiers case CONNECTION: { - UserContext context = session.getUserContext(); - // Get connection directory - Directory directory = - context.getRootConnectionGroup().getConnectionDirectory(); + UserContext context = session.getUserContext(); + Directory directory = context.getConnectionDirectory(); // Get authorized connection Connection connection = directory.get(id); @@ -232,11 +230,9 @@ public class TunnelRequestService { // Connection group identifiers case CONNECTION_GROUP: { - UserContext context = session.getUserContext(); - // Get connection group directory - Directory directory = - context.getRootConnectionGroup().getConnectionGroupDirectory(); + UserContext context = session.getUserContext(); + Directory directory = context.getConnectionGroupDirectory(); // Get authorized connection group ConnectionGroup group = directory.get(id); diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/ObjectRetrievalService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/ObjectRetrievalService.java index fb7356604..c72040493 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/ObjectRetrievalService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/ObjectRetrievalService.java @@ -89,9 +89,8 @@ public class ObjectRetrievalService { public Connection retrieveConnection(UserContext userContext, String identifier) throws GuacamoleException { - // Get root directory - ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); - Directory directory = rootGroup.getConnectionDirectory(); + // Get connection directory + Directory directory = userContext.getConnectionDirectory(); // Pull specified connection Connection connection = directory.get(identifier); @@ -125,14 +124,12 @@ public class ObjectRetrievalService { public ConnectionGroup retrieveConnectionGroup(UserContext userContext, String identifier) throws GuacamoleException { - ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); - - // Use root group if identifier is null (or the standard root identifier) + // Use root group if identifier is the standard root identifier if (identifier != null && identifier.equals(APIConnectionGroup.ROOT_IDENTIFIER)) - return rootGroup; + return userContext.getRootConnectionGroup(); // Pull specified connection group otherwise - Directory directory = rootGroup.getConnectionGroupDirectory(); + Directory directory = userContext.getConnectionGroupDirectory(); ConnectionGroup connectionGroup = directory.get(identifier); if (connectionGroup == null) diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionRESTService.java index 5e1eb7368..8c827c11c 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionRESTService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/ConnectionRESTService.java @@ -210,9 +210,7 @@ public class ConnectionRESTService { UserContext userContext = authenticationService.getUserContext(authToken); // Get the connection directory - ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); - Directory connectionDirectory = - rootGroup.getConnectionDirectory(); + Directory connectionDirectory = userContext.getConnectionDirectory(); // Delete the specified connection connectionDirectory.remove(connectionID); @@ -247,12 +245,8 @@ public class ConnectionRESTService { if (connection == null) throw new GuacamoleClientException("Connection JSON must be submitted when creating connections."); - // Retrieve parent group - String parentID = connection.getParentIdentifier(); - ConnectionGroup parentConnectionGroup = retrievalService.retrieveConnectionGroup(userContext, parentID); - // Add the new connection - Directory connectionDirectory = parentConnectionGroup.getConnectionDirectory(); + Directory connectionDirectory = userContext.getConnectionDirectory(); connectionDirectory.add(new APIConnectionWrapper(connection)); // Return the new connection identifier @@ -291,9 +285,7 @@ public class ConnectionRESTService { throw new GuacamoleClientException("Connection JSON must be submitted when updating connections."); // Get the connection directory - ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); - Directory connectionDirectory = - rootGroup.getConnectionDirectory(); + Directory connectionDirectory = userContext.getConnectionDirectory(); // Retrieve connection to update Connection existingConnection = retrievalService.retrieveConnection(userContext, connectionID); @@ -308,15 +300,6 @@ public class ConnectionRESTService { existingConnection.setName(connection.getName()); connectionDirectory.update(existingConnection); - // Get old and new parents - String oldParentIdentifier = existingConnection.getParentIdentifier(); - ConnectionGroup updatedParentGroup = retrievalService.retrieveConnectionGroup(userContext, connection.getParentIdentifier()); - - // Update connection parent, if changed - if ( (oldParentIdentifier != null && !oldParentIdentifier.equals(updatedParentGroup.getIdentifier())) - || (oldParentIdentifier == null && updatedParentGroup.getIdentifier() != null)) - connectionDirectory.move(connectionID, updatedParentGroup.getConnectionDirectory()); - } } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java index 24128bb56..a726ca169 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java @@ -22,6 +22,7 @@ package org.glyptodon.guacamole.net.basic.rest.connectiongroup; +import java.util.Set; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.net.GuacamoleSocket; import org.glyptodon.guacamole.net.auth.Connection; @@ -92,12 +93,12 @@ public class APIConnectionGroupWrapper implements ConnectionGroup { } @Override - public Directory getConnectionDirectory() throws GuacamoleException { + public Set getConnectionIdentifiers() { throw new UnsupportedOperationException("Operation not supported."); } @Override - public Directory getConnectionGroupDirectory() throws GuacamoleException { + public Set getConnectionGroupIdentifiers() { throw new UnsupportedOperationException("Operation not supported."); } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java index cab7a3550..abb686ec2 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupRESTService.java @@ -137,7 +137,7 @@ public class ConnectionGroupRESTService { // Retrieve the requested tree, filtering by the given permissions ConnectionGroup treeRoot = retrievalService.retrieveConnectionGroup(userContext, connectionGroupID); - ConnectionGroupTree tree = new ConnectionGroupTree(treeRoot, permissions); + ConnectionGroupTree tree = new ConnectionGroupTree(userContext, treeRoot, permissions); // Return tree as a connection group return tree.getRootAPIConnectionGroup(); @@ -166,9 +166,7 @@ public class ConnectionGroupRESTService { UserContext userContext = authenticationService.getUserContext(authToken); // Get the connection group directory - ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); - Directory connectionGroupDirectory = - rootGroup.getConnectionGroupDirectory(); + Directory connectionGroupDirectory = userContext.getConnectionGroupDirectory(); // Delete the connection group connectionGroupDirectory.remove(connectionGroupID); @@ -205,12 +203,8 @@ public class ConnectionGroupRESTService { if (connectionGroup == null) throw new GuacamoleClientException("Connection group JSON must be submitted when creating connections groups."); - // Retrieve parent group - String parentID = connectionGroup.getParentIdentifier(); - ConnectionGroup parentConnectionGroup = retrievalService.retrieveConnectionGroup(userContext, parentID); - // Add the new connection group - Directory connectionGroupDirectory = parentConnectionGroup.getConnectionGroupDirectory(); + Directory connectionGroupDirectory = userContext.getConnectionGroupDirectory(); connectionGroupDirectory.add(new APIConnectionGroupWrapper(connectionGroup)); // Return the new connection group identifier @@ -250,9 +244,7 @@ public class ConnectionGroupRESTService { throw new GuacamoleClientException("Connection group JSON must be submitted when updating connection groups."); // Get the connection group directory - ConnectionGroup rootGroup = userContext.getRootConnectionGroup(); - Directory connectionGroupDirectory = - rootGroup.getConnectionGroupDirectory(); + Directory connectionGroupDirectory = userContext.getConnectionGroupDirectory(); // Retrieve connection group to update ConnectionGroup existingConnectionGroup = connectionGroupDirectory.get(connectionGroupID); @@ -262,15 +254,6 @@ public class ConnectionGroupRESTService { existingConnectionGroup.setType(connectionGroup.getType()); connectionGroupDirectory.update(existingConnectionGroup); - // Get old and new parents - String oldParentIdentifier = existingConnectionGroup.getParentIdentifier(); - ConnectionGroup updatedParentGroup = retrievalService.retrieveConnectionGroup(userContext, connectionGroup.getParentIdentifier()); - - // Update connection group parent, if changed - if ( (oldParentIdentifier != null && !oldParentIdentifier.equals(updatedParentGroup.getIdentifier())) - || (oldParentIdentifier == null && updatedParentGroup.getIdentifier() != null)) - connectionGroupDirectory.move(connectionGroupID, updatedParentGroup.getConnectionGroupDirectory()); - } } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupTree.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupTree.java index f20bea7a1..5d801525c 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupTree.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/ConnectionGroupTree.java @@ -31,6 +31,7 @@ import java.util.Map; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionGroup; +import org.glyptodon.guacamole.net.auth.UserContext; import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; import org.glyptodon.guacamole.net.basic.rest.connection.APIConnection; import org.slf4j.Logger; @@ -48,11 +49,11 @@ public class ConnectionGroupTree { * Logger for this class. */ private static final Logger logger = LoggerFactory.getLogger(ConnectionGroupTree.class); - + /** - * The root connection group. + * The context of the user obtaining this tree. */ - private final ConnectionGroup root; + private final UserContext userContext; /** * The root connection group as an APIConnectionGroup. @@ -174,19 +175,19 @@ public class ConnectionGroupTree { // Build lists of identifiers for retrieval for (ConnectionGroup parent : parents) { - childConnectionIdentifiers.addAll(parent.getConnectionDirectory().getIdentifiers()); - childConnectionGroupIdentifiers.addAll(parent.getConnectionGroupDirectory().getIdentifiers()); + childConnectionIdentifiers.addAll(parent.getConnectionIdentifiers()); + childConnectionGroupIdentifiers.addAll(parent.getConnectionGroupIdentifiers()); } // Retrieve child connections if (!childConnectionIdentifiers.isEmpty()) { - Collection childConnections = root.getConnectionDirectory().getAll(childConnectionIdentifiers); + Collection childConnections = userContext.getConnectionDirectory().getAll(childConnectionIdentifiers); addConnections(childConnections); } // Retrieve child connection groups if (!childConnectionGroupIdentifiers.isEmpty()) { - Collection childConnectionGroups = root.getConnectionGroupDirectory().getAll(childConnectionGroupIdentifiers); + Collection childConnectionGroups = userContext.getConnectionGroupDirectory().getAll(childConnectionGroupIdentifiers); addConnectionGroups(childConnectionGroups); addDescendants(childConnectionGroups); } @@ -197,6 +198,9 @@ public class ConnectionGroupTree { * Creates a new connection group tree using the given connection group as * the tree root. * + * @param userContext + * The context of the user obtaining the connection group tree. + * * @param root * The connection group to use as the root of this connection group * tree. @@ -211,11 +215,12 @@ public class ConnectionGroupTree { * If an error occurs while retrieving the tree of connection groups * and their descendants. */ - public ConnectionGroupTree(ConnectionGroup root, + public ConnectionGroupTree(UserContext userContext, ConnectionGroup root, List permissions) throws GuacamoleException { + this.userContext = userContext; + // Store root of tree - this.root = root; this.rootAPIGroup = new APIConnectionGroup(root); retrievedGroups.put(root.getIdentifier(), this.rootAPIGroup); From 79130e96fcf166c5c3d6d874d1e77a25c7f7cb84 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 23 Feb 2015 13:04:25 -0800 Subject: [PATCH 18/19] GUAC-1100: Add getActiveConnections() function to Connectable. --- .../guacamole/net/auth/Connectable.java | 9 ++++ .../net/auth/simple/SimpleConnection.java | 5 +++ .../auth/simple/SimpleConnectionGroup.java | 5 +++ .../basic/rest/connection/APIConnection.java | 43 ++++++++----------- .../rest/connection/APIConnectionWrapper.java | 17 +++++++- .../connectiongroup/APIConnectionGroup.java | 28 ++++++++++++ .../APIConnectionGroupWrapper.java | 7 ++- .../app/groupList/types/GroupListItem.js | 13 +++--- .../webapp/app/home/templates/connection.html | 6 +-- .../app/manage/templates/connection.html | 6 +-- .../main/webapp/app/rest/types/Connection.js | 8 ++-- .../webapp/app/rest/types/ConnectionGroup.js | 9 ++++ 12 files changed, 112 insertions(+), 44 deletions(-) diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connectable.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connectable.java index 6ce62c916..61d2ebfd9 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connectable.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/Connectable.java @@ -51,4 +51,13 @@ public interface Connectable { public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException; + /** + * Returns the number of active connections associated with this object. + * Implementations may simply return 0 if this value is not tracked. + * + * @return + * The number of active connections associated with this object. + */ + public int getActiveConnections(); + } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnection.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnection.java index 5065ef5d7..fe5070097 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnection.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnection.java @@ -78,6 +78,11 @@ public class SimpleConnection extends AbstractConnection { } + @Override + public int getActiveConnections() { + return 0; + } + @Override public GuacamoleSocket connect(GuacamoleClientInformation info) throws GuacamoleException { diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroup.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroup.java index eb197d01a..71e73433e 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroup.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleConnectionGroup.java @@ -86,6 +86,11 @@ public class SimpleConnectionGroup extends AbstractConnectionGroup { } + @Override + public int getActiveConnections() { + return 0; + } + @Override public Set getConnectionIdentifiers() { return connectionIdentifiers; diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnection.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnection.java index 7eda11740..5b8da3f75 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnection.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnection.java @@ -22,13 +22,10 @@ package org.glyptodon.guacamole.net.basic.rest.connection; -import java.util.List; import java.util.Map; import org.codehaus.jackson.annotate.JsonIgnoreProperties; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.net.auth.Connection; -import org.glyptodon.guacamole.net.auth.ConnectionRecord; -import org.glyptodon.guacamole.net.basic.rest.connectiongroup.APIConnectionGroup; import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; /** @@ -65,9 +62,9 @@ public class APIConnection { private Map parameters; /** - * The count of currently active users for this connection. + * The count of currently active connections using this connection. */ - private int activeUsers; + private int activeConnections; /** * Create an empty APIConnection. @@ -85,23 +82,12 @@ public class APIConnection { public APIConnection(Connection connection) throws GuacamoleException { - // Set identifying information + // Set connection information this.name = connection.getName(); this.identifier = connection.getIdentifier(); - - // Set proper parent identifier, using root identifier if needed this.parentIdentifier = connection.getParentIdentifier(); - if (this.parentIdentifier == null) - this.parentIdentifier = APIConnectionGroup.ROOT_IDENTIFIER; + this.activeConnections = connection.getActiveConnections(); - // Set the number of currently active users - this.activeUsers = 0; - - for (ConnectionRecord history : connection.getHistory()) { - if (history.isActive()) - this.activeUsers++; - } - // Set protocol from configuration GuacamoleConfiguration configuration = connection.getConfiguration(); this.protocol = configuration.getProtocol(); @@ -190,19 +176,24 @@ public class APIConnection { } /** - * Returns the number of currently active users for this connection. - * @return The number of currently active users for this connection. + * Returns the number of currently active connections using this + * connection. + * + * @return + * The number of currently active usages of this connection. */ - public int getActiveUsers() { - return activeUsers; + public int getActiveConnections() { + return activeConnections; } /** - * Set the number of currently active users for this connection. - * @param activeUsers The number of currently active users for this connection. + * Set the number of currently active connections using this connection. + * + * @param activeConnections + * The number of currently active usages of this connection. */ - public void setActiveUsers(int activeUsers) { - this.activeUsers = activeUsers; + public void setActiveUsers(int activeConnections) { + this.activeConnections = activeConnections; } } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnectionWrapper.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnectionWrapper.java index 94bb5c0ed..33fe5047f 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnectionWrapper.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connection/APIConnectionWrapper.java @@ -40,8 +40,18 @@ import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; */ public class APIConnectionWrapper implements Connection { + /** + * The wrapped APIConnection. + */ private final APIConnection apiConnection; - + + /** + * Creates a new APIConnectionWrapper which wraps the given APIConnection + * as a Connection. + * + * @param apiConnection + * The APIConnection to wrap. + */ public APIConnectionWrapper(APIConnection apiConnection) { this.apiConnection = apiConnection; } @@ -76,6 +86,11 @@ public class APIConnectionWrapper implements Connection { apiConnection.setParentIdentifier(parentIdentifier); } + @Override + public int getActiveConnections() { + return apiConnection.getActiveConnections(); + } + @Override public GuacamoleConfiguration getConfiguration() { diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroup.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroup.java index 45ca049e7..b980983b5 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroup.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroup.java @@ -61,6 +61,11 @@ public class APIConnectionGroup { */ private Type type; + /** + * The count of currently active connections using this connection group. + */ + private int activeConnections; + /** * All child connection groups. If children are not being queried, this may * be omitted. @@ -91,6 +96,7 @@ public class APIConnectionGroup { this.name = connectionGroup.getName(); this.type = connectionGroup.getType(); + this.activeConnections = connectionGroup.getActiveConnections(); } @@ -206,4 +212,26 @@ public class APIConnectionGroup { this.childConnections = childConnections; } + /** + * Returns the number of currently active connections using this + * connection group. + * + * @return + * The number of currently active usages of this connection group. + */ + public int getActiveConnections() { + return activeConnections; + } + + /** + * Set the number of currently active connections using this connection + * group. + * + * @param activeConnections + * The number of currently active usages of this connection group. + */ + public void setActiveUsers(int activeConnections) { + this.activeConnections = activeConnections; + } + } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java index a726ca169..9007e75dd 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/connectiongroup/APIConnectionGroupWrapper.java @@ -25,9 +25,7 @@ package org.glyptodon.guacamole.net.basic.rest.connectiongroup; import java.util.Set; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.net.GuacamoleSocket; -import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionGroup; -import org.glyptodon.guacamole.net.auth.Directory; import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; /** @@ -92,6 +90,11 @@ public class APIConnectionGroupWrapper implements ConnectionGroup { return apiConnectionGroup.getType(); } + @Override + public int getActiveConnections() { + return apiConnectionGroup.getActiveConnections(); + } + @Override public Set getConnectionIdentifiers() { throw new UnsupportedOperationException("Operation not supported."); diff --git a/guacamole/src/main/webapp/app/groupList/types/GroupListItem.js b/guacamole/src/main/webapp/app/groupList/types/GroupListItem.js index 3f5260359..a13e0f98f 100644 --- a/guacamole/src/main/webapp/app/groupList/types/GroupListItem.js +++ b/guacamole/src/main/webapp/app/groupList/types/GroupListItem.js @@ -102,12 +102,12 @@ angular.module('groupList').factory('GroupListItem', ['ConnectionGroup', functio this.isExpanded = template.isExpanded; /** - * The number of currently active users for this connection. This field - * has no meaning for a connection group, and may be null or undefined. + * The number of currently active users for this connection or + * connection group, if known. * * @type Number */ - this.activeUsers = template.activeUsers; + this.activeConnections = template.activeConnections; /** * The connection or connection group whose data is exposed within @@ -143,8 +143,8 @@ angular.module('groupList').factory('GroupListItem', ['ConnectionGroup', functio isConnection : true, isConnectionGroup : false, - // Count of currently active users - activeUsers : connection.activeUsers, + // Count of currently active connections using this connection + activeConnections : connection.activeConnections, // Wrapped item wrappedItem : connection @@ -198,6 +198,9 @@ angular.module('groupList').factory('GroupListItem', ['ConnectionGroup', functio // Already-converted children children : children, + // Count of currently active connection groups using this connection + activeConnections : connectionGroup.activeConnections, + // Wrapped item wrappedItem : connectionGroup diff --git a/guacamole/src/main/webapp/app/home/templates/connection.html b/guacamole/src/main/webapp/app/home/templates/connection.html index 6e8bfcc28..4e91fd62d 100644 --- a/guacamole/src/main/webapp/app/home/templates/connection.html +++ b/guacamole/src/main/webapp/app/home/templates/connection.html @@ -21,7 +21,7 @@ THE SOFTWARE. --> -
+
@@ -32,8 +32,8 @@ {{item.name}} - - {{'HOME.INFO_ACTIVE_USER_COUNT' | translate:'{USERS: item.activeUsers}'}} + + {{'HOME.INFO_ACTIVE_USER_COUNT' | translate:'{USERS: item.activeConnections}'}}
diff --git a/guacamole/src/main/webapp/app/manage/templates/connection.html b/guacamole/src/main/webapp/app/manage/templates/connection.html index a1daded4e..2b65ee7d6 100644 --- a/guacamole/src/main/webapp/app/manage/templates/connection.html +++ b/guacamole/src/main/webapp/app/manage/templates/connection.html @@ -21,7 +21,7 @@ THE SOFTWARE. --> -
+
@@ -32,8 +32,8 @@ {{item.name}} - - {{'MANAGE.INFO_ACTIVE_USER_COUNT' | translate:'{USERS: item.activeUsers}'}} + + {{'MANAGE.INFO_ACTIVE_USER_COUNT' | translate:'{USERS: item.activeConnections}'}}
diff --git a/guacamole/src/main/webapp/app/rest/types/Connection.js b/guacamole/src/main/webapp/app/rest/types/Connection.js index 1a0459d7a..3c3efb87a 100644 --- a/guacamole/src/main/webapp/app/rest/types/Connection.js +++ b/guacamole/src/main/webapp/app/rest/types/Connection.js @@ -81,13 +81,13 @@ angular.module('rest').factory('Connection', [function defineConnection() { this.parameters = template.parameters; /** - * The count of currently active users for this connection. This field - * will be returned from the REST API during a get operation, - * but may not be set when doing an update or create operation. + * The count of currently active connections using this connection. + * This field will be returned from the REST API during a get + * operation, but manually setting this field will have no effect. * * @type Number */ - this.activeUsers = template.activeUsers; + this.activeConnections = template.activeConnections; }; diff --git a/guacamole/src/main/webapp/app/rest/types/ConnectionGroup.js b/guacamole/src/main/webapp/app/rest/types/ConnectionGroup.js index 89e53c6eb..cdb3fe232 100644 --- a/guacamole/src/main/webapp/app/rest/types/ConnectionGroup.js +++ b/guacamole/src/main/webapp/app/rest/types/ConnectionGroup.js @@ -91,6 +91,15 @@ angular.module('rest').factory('ConnectionGroup', [function defineConnectionGrou */ this.childConnectionGroups = template.childConnectionGroups; + /** + * The count of currently active connections using this connection + * group. This field will be returned from the REST API during a get + * operation, but manually setting this field will have no effect. + * + * @type Number + */ + this.activeConnections = template.activeConnections; + }; /** From bbabfec4da4ef3824f27d1cc5ba5dcf4d54ff8da Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 23 Feb 2015 15:37:23 -0800 Subject: [PATCH 19/19] GUAC-1100: Identifier retrieval should possibly throw an exception. --- .../guacamole/net/auth/ConnectionGroup.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionGroup.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionGroup.java index 21a1e8de6..97c66ad02 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionGroup.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionGroup.java @@ -23,6 +23,7 @@ package org.glyptodon.guacamole.net.auth; import java.util.Set; +import org.glyptodon.guacamole.GuacamoleException; /** * Represents a connection group, which can contain both other connection groups @@ -106,8 +107,11 @@ public interface ConnectionGroup extends Identifiable, Connectable { * @return * The set of identifiers of all readable connections that are children * of this connection group. + * + * @throws GuacamoleException + * If an error occurs while retrieving the identifiers. */ - public Set getConnectionIdentifiers(); + public Set getConnectionIdentifiers() throws GuacamoleException; /** * Returns the identifiers of all readable connection groups that are @@ -116,8 +120,12 @@ public interface ConnectionGroup extends Identifiable, Connectable { * @return * The set of identifiers of all readable connection groups that are * children of this connection group. + * + * @throws GuacamoleException + * If an error occurs while retrieving the identifiers. */ - public Set getConnectionGroupIdentifiers(); + public Set getConnectionGroupIdentifiers() + throws GuacamoleException; }