From a2b4b62d9f6cd1c203891b4b815743b1139f0c35 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 5 Mar 2015 14:04:34 -0800 Subject: [PATCH 01/23] GUAC-1105: Fix balancing policy semantics. --- .../AbstractGuacamoleSocketService.java | 57 +++++- .../BalancedGuacamoleSocketService.java | 88 +++++++++ .../MultiseatGuacamoleSocketService.java | 91 +++------ .../ReservedGuacamoleSocketService.java | 183 ------------------ .../guacamole/auth/jdbc/socket/Seat.java | 89 +++++++++ .../SingleSeatGuacamoleSocketService.java | 30 ++- .../UnrestrictedGuacamoleSocketService.java | 13 ++ .../mysql/MySQLAuthenticationProvider.java | 4 +- 8 files changed, 300 insertions(+), 255 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/BalancedGuacamoleSocketService.java delete mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ReservedGuacamoleSocketService.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/Seat.java diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/AbstractGuacamoleSocketService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/AbstractGuacamoleSocketService.java index 084823684..08da2decc 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/AbstractGuacamoleSocketService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/AbstractGuacamoleSocketService.java @@ -139,6 +139,37 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS protected abstract void release(AuthenticatedUser user, ModeledConnection connection); + /** + * Acquires possibly-exclusive access to the given connection group on + * behalf of the given user. If access is denied for any reason, an + * exception is thrown. + * + * @param user + * The user acquiring access. + * + * @param connectionGroup + * The connection group being accessed. + * + * @throws GuacamoleException + * If access is denied to the given user for any reason. + */ + protected abstract void acquire(AuthenticatedUser user, + ModeledConnectionGroup connectionGroup) throws GuacamoleException; + + /** + * Releases possibly-exclusive access to the given connection group on + * behalf of the given user. If the given user did not already have access, + * the behavior of this function is undefined. + * + * @param user + * The user releasing access. + * + * @param connectionGroup + * The connection group being released. + */ + protected abstract void release(AuthenticatedUser user, + ModeledConnectionGroup connectionGroup); + /** * Returns a guacamole configuration containing the protocol and parameters * from the given connection. If tokens are used in the connection @@ -254,6 +285,11 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS * @param user * The user for whom the connection is being established. * + * @param balancingGroup, + * The associated balancing group, if any. If the connection is not + * associated with a balancing group, or the connection is being used + * manually, this will be null. + * * @param connection * The connection the user is connecting to. * @@ -270,6 +306,7 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS * while connection configuration information is being retrieved. */ private GuacamoleSocket connect(final AuthenticatedUser user, + final ModeledConnectionGroup balancingGroup, final ModeledConnection connection, GuacamoleClientInformation info) throws GuacamoleException { @@ -309,6 +346,10 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS activeConnectionGroups.remove(parentIdentifier, activeConnection); release(user, connection); + // Release any associated group + if (balancingGroup != null) + release(user, balancingGroup); + // Save record to database saveConnectionRecord(identifier, activeConnection); @@ -325,9 +366,16 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS // Release connection if not already released if (released.compareAndSet(false, true)) { + + // Release connection activeConnections.remove(identifier, activeConnection); activeConnectionGroups.remove(parentIdentifier, activeConnection); release(user, connection); + + // Release any associated group + if (balancingGroup != null) + release(user, balancingGroup); + } throw e; @@ -344,7 +392,7 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS // Acquire and connect to single connection acquire(user, Collections.singletonList(connection)); - return connect(user, connection, info); + return connect(user, null, connection, info); } @@ -368,7 +416,10 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS if (identifiers.isEmpty()) throw new GuacamoleSecurityException("Permission denied."); - // Otherwise, retrieve all children + // Acquire group + acquire(user, connectionGroup); + + // Retrieve all children Collection models = connectionMapper.select(identifiers); List connections = new ArrayList(models.size()); @@ -381,7 +432,7 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS // Acquire and connect to any child ModeledConnection connection = acquire(user, connections); - return connect(user, connection, info); + return connect(user, connectionGroup, connection, info); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/BalancedGuacamoleSocketService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/BalancedGuacamoleSocketService.java new file mode 100644 index 000000000..118c0cad9 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/BalancedGuacamoleSocketService.java @@ -0,0 +1,88 @@ +/* + * 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.auth.jdbc.socket; + +import com.google.inject.Singleton; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; +import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.GuacamoleResourceConflictException; +import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; + + +/** + * GuacamoleSocketService implementation which allows only one user per + * connection at any time, but does not disallow concurrent use of connection + * groups. If a user attempts to use a connection group multiple times, they + * will receive different underlying connections each time until the group is + * exhausted. + * + * @author Michael Jumper + */ +@Singleton +public class BalancedGuacamoleSocketService + extends AbstractGuacamoleSocketService { + + /** + * The set of all active connection identifiers. + */ + private final Set activeConnections = + Collections.newSetFromMap(new ConcurrentHashMap()); + + @Override + protected ModeledConnection acquire(AuthenticatedUser user, + List connections) throws GuacamoleException { + + // Return the first unused connection + for (ModeledConnection connection : connections) { + if (activeConnections.add(connection.getIdentifier())) + return connection; + } + + // Already in use + throw new GuacamoleResourceConflictException("Cannot connect. This connection is in use."); + + } + + @Override + protected void release(AuthenticatedUser user, ModeledConnection connection) { + activeConnections.remove(connection.getIdentifier()); + } + + @Override + protected void acquire(AuthenticatedUser user, + ModeledConnectionGroup connectionGroup) throws GuacamoleException { + // Do nothing + } + + @Override + protected void release(AuthenticatedUser user, + ModeledConnectionGroup connectionGroup) { + // Do nothing + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/MultiseatGuacamoleSocketService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/MultiseatGuacamoleSocketService.java index a55e31780..d53408c73 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/MultiseatGuacamoleSocketService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/MultiseatGuacamoleSocketService.java @@ -31,12 +31,13 @@ import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleResourceConflictException; +import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; /** * GuacamoleSocketService implementation which restricts concurrency only on a - * per-user basis. Each connection may be used concurrently any number of - * times, but each concurrent use must be associated with a different user. + * per-user basis. Each connection or group may be used concurrently any number + * of times, but each concurrent use must be associated with a different user. * * @author Michael Jumper */ @@ -44,74 +45,17 @@ import org.glyptodon.guacamole.GuacamoleResourceConflictException; public class MultiseatGuacamoleSocketService extends AbstractGuacamoleSocketService { - /** - * A unique pairing of user and connection. - */ - private static class Seat { - - /** - * The user using this seat. - */ - private final String username; - - /** - * The connection associated with this seat. - */ - private final String connectionIdentifier; - - /** - * Creates a new seat which associated the given user with the given - * connection. - * - * @param username - * The username of the user using this seat. - * - * @param connectionIdentifier - * The identifier of the connection associated with this seat. - */ - public Seat(String username, String connectionIdentifier) { - this.username = username; - this.connectionIdentifier = connectionIdentifier; - } - - @Override - public int hashCode() { - - // The various properties will never be null - assert(username != null); - assert(connectionIdentifier != null); - - // Derive hashcode from username and connection identifier - int hash = 5; - hash = 37 * hash + username.hashCode(); - hash = 37 * hash + connectionIdentifier.hashCode(); - return hash; - - } - - @Override - public boolean equals(Object object) { - - // We are only comparing against other seats here - assert(object instanceof Seat); - Seat seat = (Seat) object; - - // The various properties will never be null - assert(seat.username != null); - assert(seat.connectionIdentifier != null); - - return username.equals(seat.username) - && connectionIdentifier.equals(seat.connectionIdentifier); - - } - - } - /** * The set of all active user/connection pairs. */ private final Set activeSeats = Collections.newSetFromMap(new ConcurrentHashMap()); + + /** + * The set of all active user/connection group pairs. + */ + private final Set activeGroupSeats = + Collections.newSetFromMap(new ConcurrentHashMap()); @Override protected ModeledConnection acquire(AuthenticatedUser user, @@ -135,4 +79,21 @@ public class MultiseatGuacamoleSocketService activeSeats.remove(new Seat(user.getUser().getIdentifier(), connection.getIdentifier())); } + @Override + protected void acquire(AuthenticatedUser user, + ModeledConnectionGroup connectionGroup) throws GuacamoleException { + + // Do not allow duplicate use of connection groups + Seat seat = new Seat(user.getUser().getIdentifier(), connectionGroup.getIdentifier()); + if (!activeGroupSeats.add(seat)) + throw new GuacamoleResourceConflictException("Cannot connect. This connection is in use."); + + } + + @Override + protected void release(AuthenticatedUser user, + ModeledConnectionGroup connectionGroup) { + activeGroupSeats.remove(new Seat(user.getUser().getIdentifier(), connectionGroup.getIdentifier())); + } + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ReservedGuacamoleSocketService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ReservedGuacamoleSocketService.java deleted file mode 100644 index 8cab0b814..000000000 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ReservedGuacamoleSocketService.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * 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.auth.jdbc.socket; - -import com.google.inject.Singleton; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; -import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection; -import org.glyptodon.guacamole.GuacamoleException; -import org.glyptodon.guacamole.GuacamoleResourceConflictException; - - -/** - * GuacamoleSocketService implementation which allows only one user per - * connection at any time, but does not disallow concurrent use. Once - * connected, a user has effectively reserved that connection, and may - * continue to concurrently use that connection any number of times. The - * connection will remain reserved until all associated connections are closed. - * Other users will be denied access to that connection while it is reserved. - * - * @author Michael Jumper - */ -@Singleton -public class ReservedGuacamoleSocketService - extends AbstractGuacamoleSocketService { - - /** - * An arbitrary number of reservations associated with a specific user. - * Initially, each Reservation instance represents exactly one reservation, - * but future calls to acquire() may increase this value. Once the - * reservation count is reduced to zero by calls to release(), a - * Reservation instance is empty and cannot be reused. It must be discarded - * and replaced with a fresh Reservation. - * - * This is necessary as each Reservation will be stored within a Map, and - * the effect of acquire() must be deterministic. If Reservations could be - * reused, the internal count could potentially increase after being - * removed from the map, resulting in a successful acquire() that really - * should have failed. - */ - private static class Reservation { - - /** - * The username of the user associated with this reservation. - */ - private final String username; - - /** - * The number of reservations effectively present under the associated - * username. - */ - private int count = 1; - - /** - * Creates a new reservation which tracks the overall number of - * reservations for a given user. - * @param username - */ - public Reservation(String username) { - this.username = username; - } - - /** - * Attempts to acquire a new reservation under the given username. If - * this reservation is for a different user, or the reservation has - * expired, this will fail. - * - * @param username - * The username of the user to acquire the reservation for. - * - * @return - * true if the reservation was successful, false otherwise. - */ - public boolean acquire(String username) { - - // Acquire always fails if for the wrong user - if (!this.username.equals(username)) - return false; - - // Determine success/failure based on count - synchronized (this) { - - // If already expired, no further reservations are allowed - if (count == 0) - return false; - - // Otherwise, add another reservation, report success - count++; - return true; - - } - - } - - /** - * Releases a previous reservation. The result of calling this function - * without a previous matching call to acquire is undefined. - * - * @return - * true if the last reservation has been released and this - * reservation is now empty, false otherwise. - */ - public boolean release() { - synchronized (this) { - - // Reduce reservation count - count--; - - // Empty if no reservations remain - return count == 0; - - } - } - - } - - /** - * Map of connection identifier to associated reservations. - */ - private final ConcurrentMap reservations = - new ConcurrentHashMap(); - - @Override - protected ModeledConnection acquire(AuthenticatedUser user, - List connections) throws GuacamoleException { - - String username = user.getUser().getIdentifier(); - - // Return the first successfully-reserved connection - for (ModeledConnection connection : connections) { - - String identifier = connection.getIdentifier(); - - // Attempt to reserve connection, return if successful - Reservation reservation = reservations.putIfAbsent(identifier, new Reservation(username)); - if (reservation == null || reservation.acquire(username)) - return connection; - - } - - // Already in use - throw new GuacamoleResourceConflictException("Cannot connect. This connection is in use."); - - } - - @Override - protected void release(AuthenticatedUser user, ModeledConnection connection) { - - String identifier = connection.getIdentifier(); - - // Retrieve active reservation (which must exist) - Reservation reservation = reservations.get(identifier); - assert(reservation != null); - - // Release reservation, remove from map if empty - if (reservation.release()) - reservations.remove(identifier); - - } - -} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/Seat.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/Seat.java new file mode 100644 index 000000000..275536f98 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/Seat.java @@ -0,0 +1,89 @@ +/* + * 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.auth.jdbc.socket; + +/** + * A unique pairing of user and connection or connection group. + * + * @author Michael Jumper + */ +public class Seat { + + /** + * The user using this seat. + */ + private final String username; + + /** + * The connection or connection group associated with this seat. + */ + private final String identifier; + + /** + * Creates a new seat which associated the given user with the given + * connection or connection group. + * + * @param username + * The username of the user using this seat. + * + * @param identifier + * The identifier of the connection or connection group associated with + * this seat. + */ + public Seat(String username, String identifier) { + this.username = username; + this.identifier = identifier; + } + + @Override + public int hashCode() { + + // The various properties will never be null + assert(username != null); + assert(identifier != null); + + // Derive hashcode from username and connection identifier + int hash = 5; + hash = 37 * hash + username.hashCode(); + hash = 37 * hash + identifier.hashCode(); + return hash; + + } + + @Override + public boolean equals(Object object) { + + // We are only comparing against other seats here + assert(object instanceof Seat); + Seat seat = (Seat) object; + + // The various properties will never be null + assert(seat.username != null); + assert(seat.identifier != null); + + return username.equals(seat.username) + && identifier.equals(seat.identifier); + + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/SingleSeatGuacamoleSocketService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/SingleSeatGuacamoleSocketService.java index e3ff6a9a4..b7f092565 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/SingleSeatGuacamoleSocketService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/SingleSeatGuacamoleSocketService.java @@ -31,11 +31,14 @@ import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleResourceConflictException; +import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; /** * GuacamoleSocketService implementation which allows exactly one use - * of any connection at any time. Concurrent usage of any kind is not allowed. + * of any connection at any time. Concurrent usage of connections is not + * allowed, and concurrent usage of connection groups is allowed only between + * different users. * * @author Michael Jumper */ @@ -48,7 +51,13 @@ public class SingleSeatGuacamoleSocketService */ private final Set activeConnections = Collections.newSetFromMap(new ConcurrentHashMap()); - + + /** + * The set of all active user/connection group pairs. + */ + private final Set activeGroupSeats = + Collections.newSetFromMap(new ConcurrentHashMap()); + @Override protected ModeledConnection acquire(AuthenticatedUser user, List connections) throws GuacamoleException { @@ -69,4 +78,21 @@ public class SingleSeatGuacamoleSocketService activeConnections.remove(connection.getIdentifier()); } + @Override + protected void acquire(AuthenticatedUser user, + ModeledConnectionGroup connectionGroup) throws GuacamoleException { + + // Do not allow duplicate use of connection groups + Seat seat = new Seat(user.getUser().getIdentifier(), connectionGroup.getIdentifier()); + if (!activeGroupSeats.add(seat)) + throw new GuacamoleResourceConflictException("Cannot connect. This connection is in use."); + + } + + @Override + protected void release(AuthenticatedUser user, + ModeledConnectionGroup connectionGroup) { + activeGroupSeats.remove(new Seat(user.getUser().getIdentifier(), connectionGroup.getIdentifier())); + } + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/UnrestrictedGuacamoleSocketService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/UnrestrictedGuacamoleSocketService.java index c5d2a0503..e5932d8c2 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/UnrestrictedGuacamoleSocketService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/UnrestrictedGuacamoleSocketService.java @@ -27,6 +27,7 @@ import java.util.List; import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection; import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; /** @@ -66,4 +67,16 @@ public class UnrestrictedGuacamoleSocketService // Do nothing } + @Override + protected void acquire(AuthenticatedUser user, + ModeledConnectionGroup connectionGroup) throws GuacamoleException { + // Do nothing + } + + @Override + protected void release(AuthenticatedUser user, + ModeledConnectionGroup connectionGroup) { + // Do nothing + } + } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java index c33787a38..3e7463b69 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/java/net/sourceforge/guacamole/net/auth/mysql/MySQLAuthenticationProvider.java @@ -31,7 +31,7 @@ import org.glyptodon.guacamole.net.auth.UserContext; import org.glyptodon.guacamole.auth.jdbc.JDBCAuthenticationProviderModule; import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService; import org.glyptodon.guacamole.auth.jdbc.socket.MultiseatGuacamoleSocketService; -import org.glyptodon.guacamole.auth.jdbc.socket.ReservedGuacamoleSocketService; +import org.glyptodon.guacamole.auth.jdbc.socket.BalancedGuacamoleSocketService; import org.glyptodon.guacamole.auth.jdbc.socket.SingleSeatGuacamoleSocketService; import org.glyptodon.guacamole.auth.jdbc.socket.UnrestrictedGuacamoleSocketService; import org.glyptodon.guacamole.auth.jdbc.user.UserContextService; @@ -85,7 +85,7 @@ public class MySQLAuthenticationProvider implements AuthenticationProvider { // Connections are reserved for a single user when in use else - return ReservedGuacamoleSocketService.class; + return BalancedGuacamoleSocketService.class; } From 331772865804188f8d8a195f5a1909c32c4493a0 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 5 Mar 2015 15:21:56 -0800 Subject: [PATCH 02/23] GUAC-1105: Find first available, least-used seat in multiseat policy. --- .../MultiseatGuacamoleSocketService.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/MultiseatGuacamoleSocketService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/MultiseatGuacamoleSocketService.java index d53408c73..aa1786f6f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/MultiseatGuacamoleSocketService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/MultiseatGuacamoleSocketService.java @@ -23,7 +23,9 @@ package org.glyptodon.guacamole.auth.jdbc.socket; import com.google.inject.Singleton; +import java.util.Arrays; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -62,9 +64,23 @@ public class MultiseatGuacamoleSocketService List connections) throws GuacamoleException { String username = user.getUser().getIdentifier(); + + // Sort connections in ascending order of usage + ModeledConnection[] sortedConnections = connections.toArray(new ModeledConnection[connections.size()]); + Arrays.sort(sortedConnections, new Comparator() { + + @Override + public int compare(ModeledConnection a, ModeledConnection b) { + + return getActiveConnections(a).size() + - getActiveConnections(b).size(); + + } + + }); // Return the first unreserved connection - for (ModeledConnection connection : connections) { + for (ModeledConnection connection : sortedConnections) { if (activeSeats.add(new Seat(username, connection.getIdentifier()))) return connection; } From 31661144301c86246cf9f9f2446b603911525c3d Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 5 Mar 2015 15:25:42 -0800 Subject: [PATCH 03/23] GUAC-1105: Throw GuacamoleClientTooManyException if connection group usage is denied due to duplicate use. --- .../auth/jdbc/socket/MultiseatGuacamoleSocketService.java | 3 ++- .../auth/jdbc/socket/SingleSeatGuacamoleSocketService.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/MultiseatGuacamoleSocketService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/MultiseatGuacamoleSocketService.java index aa1786f6f..867c1b5d0 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/MultiseatGuacamoleSocketService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/MultiseatGuacamoleSocketService.java @@ -29,6 +29,7 @@ import java.util.Comparator; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import org.glyptodon.guacamole.GuacamoleClientTooManyException; import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection; import org.glyptodon.guacamole.GuacamoleException; @@ -102,7 +103,7 @@ public class MultiseatGuacamoleSocketService // Do not allow duplicate use of connection groups Seat seat = new Seat(user.getUser().getIdentifier(), connectionGroup.getIdentifier()); if (!activeGroupSeats.add(seat)) - throw new GuacamoleResourceConflictException("Cannot connect. This connection is in use."); + throw new GuacamoleClientTooManyException("Cannot connect. Connection group already in use by this user."); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/SingleSeatGuacamoleSocketService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/SingleSeatGuacamoleSocketService.java index b7f092565..383e85f66 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/SingleSeatGuacamoleSocketService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/SingleSeatGuacamoleSocketService.java @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.List; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import org.glyptodon.guacamole.GuacamoleClientTooManyException; import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection; import org.glyptodon.guacamole.GuacamoleException; @@ -85,7 +86,7 @@ public class SingleSeatGuacamoleSocketService // Do not allow duplicate use of connection groups Seat seat = new Seat(user.getUser().getIdentifier(), connectionGroup.getIdentifier()); if (!activeGroupSeats.add(seat)) - throw new GuacamoleResourceConflictException("Cannot connect. This connection is in use."); + throw new GuacamoleClientTooManyException("Cannot connect. Connection group already in use by this user."); } From 9d6828bf3a8fc04d9543a626c6813d2195151c9d Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 5 Mar 2015 16:36:50 -0800 Subject: [PATCH 04/23] GUAC-1105: Reduce code complexity of AbstractGuacamoleSocketService. --- .../AbstractGuacamoleSocketService.java | 243 ++++++++++-------- .../jdbc/socket/ActiveConnectionRecord.java | 83 +++++- .../socket/ManagedInetGuacamoleSocket.java | 71 +++++ 3 files changed, 289 insertions(+), 108 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ManagedInetGuacamoleSocket.java diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/AbstractGuacamoleSocketService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/AbstractGuacamoleSocketService.java index 08da2decc..7647ff54d 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/AbstractGuacamoleSocketService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/AbstractGuacamoleSocketService.java @@ -44,7 +44,6 @@ import org.glyptodon.guacamole.GuacamoleSecurityException; import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionMapper; import org.glyptodon.guacamole.environment.Environment; import org.glyptodon.guacamole.net.GuacamoleSocket; -import org.glyptodon.guacamole.net.InetGuacamoleSocket; import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionGroup; import org.glyptodon.guacamole.net.auth.ConnectionRecord; @@ -214,19 +213,17 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS } /** - * Saves the given ActiveConnectionRecord to the database, associating it - * with the connection having the given identifier. The end date of the - * saved record will be populated with the current time. - * - * @param identifier - * The connection to associate the new record with. + * Saves the given ActiveConnectionRecord to the database. The end date of + * the saved record will be populated with the current time. * * @param record * The record to save. */ - private void saveConnectionRecord(String identifier, - ActiveConnectionRecord record) { + private void saveConnectionRecord(ActiveConnectionRecord record) { + // Get associated connection + ModeledConnection connection = record.getConnection(); + // Get associated models AuthenticatedUser user = record.getUser(); UserModel userModel = user.getUser().getModel(); @@ -235,7 +232,7 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS // Copy user information and timestamps into new record recordModel.setUserID(userModel.getObjectID()); recordModel.setUsername(userModel.getIdentifier()); - recordModel.setConnectionIdentifier(identifier); + recordModel.setConnectionIdentifier(connection.getIdentifier()); recordModel.setStartDate(record.getStartDate()); recordModel.setEndDate(new Date()); @@ -255,24 +252,88 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS * If an error occurs while connecting to guacd, or while parsing * guacd-related properties. */ - private GuacamoleSocket getUnconfiguredGuacamoleSocket() + private GuacamoleSocket getUnconfiguredGuacamoleSocket(Runnable socketClosedCallback) throws GuacamoleException { // Use SSL if requested if (environment.getProperty(Environment.GUACD_SSL, true)) - return new InetGuacamoleSocket( + return new ManagedInetGuacamoleSocket( environment.getRequiredProperty(Environment.GUACD_HOSTNAME), - environment.getRequiredProperty(Environment.GUACD_PORT) + environment.getRequiredProperty(Environment.GUACD_PORT), + socketClosedCallback ); // Otherwise, just use straight TCP - return new InetGuacamoleSocket( + return new ManagedInetGuacamoleSocket( environment.getRequiredProperty(Environment.GUACD_HOSTNAME), - environment.getRequiredProperty(Environment.GUACD_PORT) + environment.getRequiredProperty(Environment.GUACD_PORT), + socketClosedCallback ); } - + + /** + * Task which handles cleanup of a connection associated with some given + * ActiveConnectionRecord. + */ + private class ConnectionCleanupTask implements Runnable { + + /** + * Whether this task has run. + */ + private final AtomicBoolean hasRun = new AtomicBoolean(false); + + /** + * The ActiveConnectionRecord whose connection will be cleaned up once + * this task runs. + */ + private final ActiveConnectionRecord activeConnection; + + /** + * Creates a new task which automatically cleans up after the + * connection associated with the given ActiveConnectionRecord. The + * connection and parent group will be removed from the maps of active + * connections and groups, and exclusive access will be released. + * + * @param activeConnection + * The ActiveConnectionRecord whose associated connection should be + * cleaned up once this task runs. + */ + public ConnectionCleanupTask(ActiveConnectionRecord activeConnection) { + this.activeConnection = activeConnection; + } + + @Override + public void run() { + + // Only run once + if (!hasRun.compareAndSet(false, true)) + return; + + // Get original user and connection + AuthenticatedUser user = activeConnection.getUser(); + ModeledConnection connection = activeConnection.getConnection(); + + // Get associated identifiers + String identifier = connection.getIdentifier(); + String parentIdentifier = connection.getParentIdentifier(); + + // Release connection + activeConnections.remove(identifier, activeConnection); + activeConnectionGroups.remove(parentIdentifier, activeConnection); + release(user, connection); + + // Release any associated group + if (activeConnection.hasBalancingGroup()) + release(user, activeConnection.getBalancingGroup()); + + // Save history record to database + saveConnectionRecord(activeConnection); + + } + + } + /** * Creates a socket for the given user which connects to the given * connection, which MUST already be acquired via acquire(). The given @@ -285,11 +346,6 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS * @param user * The user for whom the connection is being established. * - * @param balancingGroup, - * The associated balancing group, if any. If the connection is not - * associated with a balancing group, or the connection is being used - * manually, this will be null. - * * @param connection * The connection the user is connecting to. * @@ -305,85 +361,77 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS * If an error occurs while the connection is being established, or * while connection configuration information is being retrieved. */ - private GuacamoleSocket connect(final AuthenticatedUser user, - final ModeledConnectionGroup balancingGroup, - final ModeledConnection connection, GuacamoleClientInformation info) + private GuacamoleSocket getGuacamoleSocket(ActiveConnectionRecord activeConnection, + GuacamoleClientInformation info) throws GuacamoleException { - // Create record for active connection - final ActiveConnectionRecord activeConnection = new ActiveConnectionRecord(user); + ModeledConnection connection = activeConnection.getConnection(); + + // Record new active connection + Runnable cleanupTask = new ConnectionCleanupTask(activeConnection); + activeConnections.put(connection.getIdentifier(), activeConnection); + activeConnectionGroups.put(connection.getParentIdentifier(), activeConnection); - // Get relevant identifiers - final AtomicBoolean released = new AtomicBoolean(false); - final String identifier = connection.getIdentifier(); - final String parentIdentifier = connection.getParentIdentifier(); - // Return new socket try { - - // Record new active connection - activeConnections.put(identifier, activeConnection); - activeConnectionGroups.put(parentIdentifier, activeConnection); - - // Return newly-reserved connection return new ConfiguredGuacamoleSocket( - getUnconfiguredGuacamoleSocket(), - getGuacamoleConfiguration(user, connection), + getUnconfiguredGuacamoleSocket(cleanupTask), + getGuacamoleConfiguration(activeConnection.getUser(), connection), info - ) { - - @Override - public void close() throws GuacamoleException { - - // Attempt to close connection - super.close(); - - // Release connection upon close, if not already released - if (released.compareAndSet(false, true)) { - - // Release connection - activeConnections.remove(identifier, activeConnection); - activeConnectionGroups.remove(parentIdentifier, activeConnection); - release(user, connection); - - // Release any associated group - if (balancingGroup != null) - release(user, balancingGroup); - - // Save record to database - saveConnectionRecord(identifier, activeConnection); - - } - - } // end close() - - }; - + ); } - // Release connection in case of error + // Execute cleanup if socket could not be created catch (GuacamoleException e) { - - // Release connection if not already released - if (released.compareAndSet(false, true)) { - - // Release connection - activeConnections.remove(identifier, activeConnection); - activeConnectionGroups.remove(parentIdentifier, activeConnection); - release(user, connection); - - // Release any associated group - if (balancingGroup != null) - release(user, balancingGroup); - - } - + cleanupTask.run(); throw e; - } } + /** + * Returns a list of all balanced connections within a given connection + * group. If the connection group is not balancing, or it contains no + * connections, an empty list is returned. + * + * @param user + * The user on whose behalf the balanced connections within the given + * connection group are being retrieved. + * + * @param connectionGroup + * The connection group to retrieve the balanced connections of. + * + * @return + * A list containing all balanced connections within the given group, + * or an empty list if there are no such connections. + */ + private List getBalancedConnections(AuthenticatedUser user, + ModeledConnectionGroup connectionGroup) { + + // If not a balancing group, there are no balanced connections + if (connectionGroup.getType() != ConnectionGroup.Type.BALANCING) + return Collections.EMPTY_LIST; + + // If group has no children, there are no balanced connections + Collection identifiers = connectionMapper.selectIdentifiersWithin(connectionGroup.getIdentifier()); + if (identifiers.isEmpty()) + return Collections.EMPTY_LIST; + + // Retrieve all children + Collection models = connectionMapper.select(identifiers); + List connections = new ArrayList(models.size()); + + // Convert each retrieved model to a modeled connection + for (ConnectionModel model : models) { + ModeledConnection connection = connectionProvider.get(); + connection.init(user, model); + connections.add(connection); + } + + return connections; + + } + @Override @Transactional public GuacamoleSocket getGuacamoleSocket(final AuthenticatedUser user, @@ -392,7 +440,7 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS // Acquire and connect to single connection acquire(user, Collections.singletonList(connection)); - return connect(user, null, connection, info); + return getGuacamoleSocket(new ActiveConnectionRecord(user, connection), info); } @@ -407,32 +455,17 @@ public abstract class AbstractGuacamoleSocketService implements GuacamoleSocketS ModeledConnectionGroup connectionGroup, GuacamoleClientInformation info) throws GuacamoleException { - // If not a balancing group, cannot connect - if (connectionGroup.getType() != ConnectionGroup.Type.BALANCING) - throw new GuacamoleSecurityException("Permission denied."); - - // If group has no children, cannot connect - Collection identifiers = connectionMapper.selectIdentifiersWithin(connectionGroup.getIdentifier()); - if (identifiers.isEmpty()) + // If group has no associated balanced connections, cannot connect + List connections = getBalancedConnections(user, connectionGroup); + if (connections.isEmpty()) throw new GuacamoleSecurityException("Permission denied."); // Acquire group acquire(user, connectionGroup); - // Retrieve all children - Collection models = connectionMapper.select(identifiers); - List connections = new ArrayList(models.size()); - - // Convert each retrieved model to a modeled connection - for (ConnectionModel model : models) { - ModeledConnection connection = connectionProvider.get(); - connection.init(user, model); - connections.add(connection); - } - // Acquire and connect to any child ModeledConnection connection = acquire(user, connections); - return connect(user, connectionGroup, connection, info); + return getGuacamoleSocket(new ActiveConnectionRecord(user, connectionGroup, connection), info); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ActiveConnectionRecord.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ActiveConnectionRecord.java index e6d520b87..5d23a7443 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ActiveConnectionRecord.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ActiveConnectionRecord.java @@ -23,6 +23,8 @@ package org.glyptodon.guacamole.auth.jdbc.socket; import java.util.Date; +import org.glyptodon.guacamole.auth.jdbc.connection.ModeledConnection; +import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ModeledConnectionGroup; import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; import org.glyptodon.guacamole.net.auth.ConnectionRecord; @@ -43,21 +45,62 @@ public class ActiveConnectionRecord implements ConnectionRecord { */ private final AuthenticatedUser user; + /** + * The balancing group from which the associated connection was chosen, if + * any. If no balancing group was used, this will be null. + */ + private final ModeledConnectionGroup balancingGroup; + + /** + * The connection associated with this connection record. + */ + private final ModeledConnection connection; + /** * The time this connection record was created. */ private final Date startDate = new Date(); /** - * Creates a new connection record associated with the given user. The - * start date of this connection record will be the time of its creation. + * Creates a new connection record associated with the given user, + * connection, and balancing connection group. The given balancing + * connection group MUST be the connection group from which the given + * connection was chosen. The start date of this connection record will be + * the time of its creation. * * @param user * The user that connected to the connection associated with this * connection record. + * + * @param balancingGroup + * The balancing group from which the given connection was chosen. + * + * @param connection + * The connection to associate with this connection record. */ - public ActiveConnectionRecord(AuthenticatedUser user) { + public ActiveConnectionRecord(AuthenticatedUser user, + ModeledConnectionGroup balancingGroup, + ModeledConnection connection) { this.user = user; + this.balancingGroup = balancingGroup; + this.connection = connection; + } + + /** + * Creates a new connection record associated with the given user and + * connection. The start date of this connection record will be the time of + * its creation. + * + * @param user + * The user that connected to the connection associated with this + * connection record. + * + * @param connection + * The connection to associate with this connection record. + */ + public ActiveConnectionRecord(AuthenticatedUser user, + ModeledConnection connection) { + this(user, null, connection); } /** @@ -72,6 +115,40 @@ public class ActiveConnectionRecord implements ConnectionRecord { return user; } + /** + * Returns the balancing group from which the connection associated with + * this connection record was chosen. + * + * @return + * The balancing group from which the connection associated with this + * connection record was chosen. + */ + public ModeledConnectionGroup getBalancingGroup() { + return balancingGroup; + } + + /** + * Returns the connection associated with this connection record. + * + * @return + * The connection associated with this connection record. + */ + public ModeledConnection getConnection() { + return connection; + } + + /** + * Returns whether the connection associated with this connection record + * was chosen from a balancing group. + * + * @return + * true if the connection associated with this connection record was + * chosen from a balancing group, false otherwise. + */ + public boolean hasBalancingGroup() { + return balancingGroup != null; + } + @Override public Date getStartDate() { return startDate; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ManagedInetGuacamoleSocket.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ManagedInetGuacamoleSocket.java new file mode 100644 index 000000000..8658bba4c --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/socket/ManagedInetGuacamoleSocket.java @@ -0,0 +1,71 @@ +/* + * 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.auth.jdbc.socket; + +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.net.InetGuacamoleSocket; + +/** + * Implementation of GuacamoleSocket which connects via TCP to a given hostname + * and port. If the socket is closed for any reason, a given task is run. + * + * @author Michael Jumper + */ +public class ManagedInetGuacamoleSocket extends InetGuacamoleSocket { + + /** + * The task to run when the socket is closed. + */ + private final Runnable socketClosedTask; + + /** + * Creates a new socket which connects via TCP to a given hostname and + * port. If the socket is closed for any reason, the given task is run. + * + * @param hostname + * The hostname of the Guacamole proxy server to connect to. + * + * @param port + * The port of the Guacamole proxy server to connect to. + * + * @param socketClosedTask + * The task to run when the socket is closed. This task will NOT be + * run if an exception occurs during connection, and this + * ManagedInetGuacamoleSocket instance is ultimately not created. + * + * @throws GuacamoleException + * If an error occurs while connecting to the Guacamole proxy server. + */ + public ManagedInetGuacamoleSocket(String hostname, int port, + Runnable socketClosedTask) throws GuacamoleException { + super(hostname, port); + this.socketClosedTask = socketClosedTask; + } + + @Override + public void close() throws GuacamoleException { + super.close(); + socketClosedTask.run(); + } + +} From 8ae0215e5f38db48cd1a0f599e17433c6596a67d Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 5 Mar 2015 17:35:30 -0800 Subject: [PATCH 05/23] GUAC-1113: Require only READ to read another user's permissions. --- .../permission/ObjectPermissionService.java | 14 +++--- .../jdbc/permission/PermissionService.java | 43 +++++++++++++++++-- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ObjectPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ObjectPermissionService.java index 79ce6407e..4e3beb0e1 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ObjectPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/ObjectPermissionService.java @@ -185,9 +185,8 @@ public abstract class ObjectPermissionService ModeledUser targetUser, ObjectPermission.Type type, String identifier) throws GuacamoleException { - // Only an admin can read permissions that aren't his own - if (user.getUser().getIdentifier().equals(targetUser.getIdentifier()) - || user.getUser().isAdministrator()) { + // Retrieve permissions only if allowed + if (canReadPermissions(user, targetUser)) { // Read permission from database, return null if not found ObjectPermissionModel model = getPermissionMapper().selectOne(targetUser.getModel(), type, identifier); @@ -237,14 +236,11 @@ public abstract class ObjectPermissionService if (identifiers.isEmpty()) return identifiers; - // Determine whether the user is an admin - boolean isAdmin = user.getUser().isAdministrator(); - - // Only an admin can read permissions that aren't his own - if (isAdmin || user.getUser().getIdentifier().equals(targetUser.getIdentifier())) { + // Retrieve permissions only if allowed + if (canReadPermissions(user, targetUser)) { // If user is an admin, everything is accessible - if (isAdmin) + if (user.getUser().isAdministrator()) return identifiers; // Otherwise, return explicitly-retrievable identifiers diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/PermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/PermissionService.java index 3207ffc8d..b4c35ba5e 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/PermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/PermissionService.java @@ -30,6 +30,8 @@ import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; import org.glyptodon.guacamole.auth.jdbc.user.ModeledUser; 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; import org.glyptodon.guacamole.net.auth.permission.Permission; import org.glyptodon.guacamole.net.auth.permission.PermissionSet; @@ -141,6 +143,42 @@ public abstract class PermissionService retrievePermissions(AuthenticatedUser user, ModeledUser targetUser) throws GuacamoleException { - // Only an admin can read permissions that aren't his own - if (user.getUser().getIdentifier().equals(targetUser.getIdentifier()) - || user.getUser().isAdministrator()) + // Retrieve permissions only if allowed + if (canReadPermissions(user, targetUser)) return getPermissionInstances(getPermissionMapper().select(targetUser.getModel())); // User cannot read this user's permissions From 15240cc7b11479bdb393e7665167c68dcf91ecaa Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 2 Mar 2015 12:21:24 -0800 Subject: [PATCH 06/23] GUAC-1103: Add stubbed PostgreSQL authentication by copying the MySQL auth. Has not yet been tested against an actual DB nor the PostgreSQL JDBC driver. --- .../guacamole-auth-jdbc-postgresql/.gitignore | 2 + .../guacamole-auth-jdbc-postgresql/pom.xml | 78 ++++++ .../schema/001-create-schema.sql | 228 ++++++++++++++++++ .../schema/002-create-admin-user.sql | 38 +++ .../PostgreSQLAuthenticationProvider.java | 151 ++++++++++++ ...ostgreSQLAuthenticationProviderModule.java | 99 ++++++++ .../PostgreSQLGuacamoleProperties.java | 127 ++++++++++ .../auth/postgresql/package-info.java | 26 ++ .../auth/jdbc/connection/ConnectionMapper.xml | 158 ++++++++++++ .../connection/ConnectionRecordMapper.xml | 75 ++++++ .../auth/jdbc/connection/ParameterMapper.xml | 71 ++++++ .../connectiongroup/ConnectionGroupMapper.xml | 159 ++++++++++++ .../ConnectionGroupPermissionMapper.xml | 120 +++++++++ .../permission/ConnectionPermissionMapper.xml | 120 +++++++++ .../permission/SystemPermissionMapper.xml | 93 +++++++ .../jdbc/permission/UserPermissionMapper.xml | 129 ++++++++++ .../guacamole/auth/jdbc/user/UserMapper.xml | 135 +++++++++++ extensions/guacamole-auth-jdbc/pom.xml | 3 +- 18 files changed, 1811 insertions(+), 1 deletion(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/.gitignore create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/pom.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProvider.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLGuacamoleProperties.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/package-info.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ParameterMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/user/UserMapper.xml diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/.gitignore b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/.gitignore new file mode 100644 index 000000000..42f4a1a64 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/.gitignore @@ -0,0 +1,2 @@ +target/ +*~ diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/pom.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/pom.xml new file mode 100644 index 000000000..2329087cd --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/pom.xml @@ -0,0 +1,78 @@ + + + 4.0.0 + org.glyptodon.guacamole + guacamole-auth-jdbc-postgresql + jar + guacamole-auth-jdbc-postgresql + http://guac-dev.org/ + + + UTF-8 + + + + org.glyptodon.guacamole + guacamole-auth-jdbc + 0.9.5 + ../../ + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.6 + 1.6 + + + + + + maven-assembly-plugin + 2.2-beta-5 + + + jar-with-dependencies + package + + single + + + extension/${project.artifactId}-${project.version} + false + + jar-with-dependencies + + + + + + + + + + + + + + org.glyptodon.guacamole + guacamole-ext + provided + + + + + org.glyptodon.guacamole + guacamole-auth-jdbc-base + 0.9.5 + + + + + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql new file mode 100644 index 000000000..5c23bfc90 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql @@ -0,0 +1,228 @@ +-- +-- 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. +-- + +-- +-- Table of connection groups. Each connection group has a name. +-- + +CREATE TABLE `guacamole_connection_group` ( + + `connection_group_id` int(11) NOT NULL AUTO_INCREMENT, + `parent_id` int(11), + `connection_group_name` varchar(128) NOT NULL, + `type` enum('ORGANIZATIONAL', + 'BALANCING') NOT NULL DEFAULT 'ORGANIZATIONAL', + + PRIMARY KEY (`connection_group_id`), + UNIQUE KEY `connection_group_name_parent` (`connection_group_name`, `parent_id`), + + CONSTRAINT `guacamole_connection_group_ibfk_1` + FOREIGN KEY (`parent_id`) + REFERENCES `guacamole_connection_group` (`connection_group_id`) ON DELETE CASCADE + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table of connections. Each connection has a name, protocol, and +-- associated set of parameters. +-- A connection may belong to a connection group. +-- + +CREATE TABLE `guacamole_connection` ( + + `connection_id` int(11) NOT NULL AUTO_INCREMENT, + `connection_name` varchar(128) NOT NULL, + `parent_id` int(11), + `protocol` varchar(32) NOT NULL, + + PRIMARY KEY (`connection_id`), + UNIQUE KEY `connection_name_parent` (`connection_name`, `parent_id`), + + CONSTRAINT `guacamole_connection_ibfk_1` + FOREIGN KEY (`parent_id`) + REFERENCES `guacamole_connection_group` (`connection_group_id`) ON DELETE CASCADE + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table of users. Each user has a unique username and a hashed password +-- with corresponding salt. +-- + +CREATE TABLE `guacamole_user` ( + + `user_id` int(11) NOT NULL AUTO_INCREMENT, + `username` varchar(128) NOT NULL, + `password_hash` binary(32) NOT NULL, + `password_salt` binary(32) NOT NULL, + + PRIMARY KEY (`user_id`), + UNIQUE KEY `username` (`username`) + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table of connection parameters. Each parameter is simply a name/value pair +-- associated with a connection. +-- + +CREATE TABLE `guacamole_connection_parameter` ( + + `connection_id` int(11) NOT NULL, + `parameter_name` varchar(128) NOT NULL, + `parameter_value` varchar(4096) NOT NULL, + + PRIMARY KEY (`connection_id`,`parameter_name`), + + CONSTRAINT `guacamole_connection_parameter_ibfk_1` + FOREIGN KEY (`connection_id`) + REFERENCES `guacamole_connection` (`connection_id`) ON DELETE CASCADE + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table of connection permissions. Each connection permission grants a user +-- specific access to a connection. +-- + +CREATE TABLE `guacamole_connection_permission` ( + + `user_id` int(11) NOT NULL, + `connection_id` int(11) NOT NULL, + `permission` enum('READ', + 'UPDATE', + 'DELETE', + 'ADMINISTER') NOT NULL, + + PRIMARY KEY (`user_id`,`connection_id`,`permission`), + + CONSTRAINT `guacamole_connection_permission_ibfk_1` + FOREIGN KEY (`connection_id`) + REFERENCES `guacamole_connection` (`connection_id`) ON DELETE CASCADE, + + CONSTRAINT `guacamole_connection_permission_ibfk_2` + FOREIGN KEY (`user_id`) + REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table of connection group permissions. Each group permission grants a user +-- specific access to a connection group. +-- + +CREATE TABLE `guacamole_connection_group_permission` ( + + `user_id` int(11) NOT NULL, + `connection_group_id` int(11) NOT NULL, + `permission` enum('READ', + 'UPDATE', + 'DELETE', + 'ADMINISTER') NOT NULL, + + PRIMARY KEY (`user_id`,`connection_group_id`,`permission`), + + CONSTRAINT `guacamole_connection_group_permission_ibfk_1` + FOREIGN KEY (`connection_group_id`) + REFERENCES `guacamole_connection_group` (`connection_group_id`) ON DELETE CASCADE, + + CONSTRAINT `guacamole_connection_group_permission_ibfk_2` + FOREIGN KEY (`user_id`) + REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table of system permissions. Each system permission grants a user a +-- system-level privilege of some kind. +-- + +CREATE TABLE `guacamole_system_permission` ( + + `user_id` int(11) NOT NULL, + `permission` enum('CREATE_CONNECTION', + 'CREATE_CONNECTION_GROUP', + 'CREATE_USER', + 'ADMINISTER') NOT NULL, + + PRIMARY KEY (`user_id`,`permission`), + + CONSTRAINT `guacamole_system_permission_ibfk_1` + FOREIGN KEY (`user_id`) + REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table of user permissions. Each user permission grants a user access to +-- another user (the "affected" user) for a specific type of operation. +-- + +CREATE TABLE `guacamole_user_permission` ( + + `user_id` int(11) NOT NULL, + `affected_user_id` int(11) NOT NULL, + `permission` enum('READ', + 'UPDATE', + 'DELETE', + 'ADMINISTER') NOT NULL, + + PRIMARY KEY (`user_id`,`affected_user_id`,`permission`), + + CONSTRAINT `guacamole_user_permission_ibfk_1` + FOREIGN KEY (`affected_user_id`) + REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE, + + CONSTRAINT `guacamole_user_permission_ibfk_2` + FOREIGN KEY (`user_id`) + REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Table of connection history records. Each record defines a specific user's +-- session, including the connection used, the start time, and the end time +-- (if any). +-- + +CREATE TABLE `guacamole_connection_history` ( + + `history_id` int(11) NOT NULL AUTO_INCREMENT, + `user_id` int(11) NOT NULL, + `connection_id` int(11) NOT NULL, + `start_date` datetime NOT NULL, + `end_date` datetime DEFAULT NULL, + + PRIMARY KEY (`history_id`), + KEY `user_id` (`user_id`), + KEY `connection_id` (`connection_id`), + + CONSTRAINT `guacamole_connection_history_ibfk_1` + FOREIGN KEY (`user_id`) + REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE, + + CONSTRAINT `guacamole_connection_history_ibfk_2` + FOREIGN KEY (`connection_id`) + REFERENCES `guacamole_connection` (`connection_id`) ON DELETE CASCADE + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql new file mode 100644 index 000000000..997a48841 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql @@ -0,0 +1,38 @@ +-- +-- 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. +-- + +-- Create default user "guacadmin" with password "guacadmin" +insert into guacamole_user values(1, 'guacadmin', + x'CA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960', -- 'guacadmin' + x'FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264'); + +-- Grant this user create permissions +insert into guacamole_system_permission values(1, 'CREATE_CONNECTION'); +insert into guacamole_system_permission values(1, 'CREATE_CONNECTION_GROUP'); +insert into guacamole_system_permission values(1, 'CREATE_USER'); +insert into guacamole_system_permission values(1, 'ADMINISTER'); + +-- Grant admin permission to read/update/administer self +insert into guacamole_user_permission values(1, 1, 'READ'); +insert into guacamole_user_permission values(1, 1, 'UPDATE'); +insert into guacamole_user_permission values(1, 1, 'ADMINISTER'); + diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProvider.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProvider.java new file mode 100644 index 000000000..65bd2270a --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProvider.java @@ -0,0 +1,151 @@ +/* + * 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.auth.postgresql; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.net.auth.AuthenticationProvider; +import org.glyptodon.guacamole.net.auth.Credentials; +import org.glyptodon.guacamole.net.auth.UserContext; +import org.glyptodon.guacamole.auth.jdbc.JDBCAuthenticationProviderModule; +import org.glyptodon.guacamole.auth.jdbc.socket.BalancedGuacamoleSocketService; +import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService; +import org.glyptodon.guacamole.auth.jdbc.socket.MultiseatGuacamoleSocketService; +import org.glyptodon.guacamole.auth.jdbc.socket.SingleSeatGuacamoleSocketService; +import org.glyptodon.guacamole.auth.jdbc.socket.UnrestrictedGuacamoleSocketService; +import org.glyptodon.guacamole.auth.jdbc.user.UserContextService; +import org.glyptodon.guacamole.environment.Environment; +import org.glyptodon.guacamole.environment.LocalEnvironment; + +/** + * Provides a PostgreSQL-based implementation of the AuthenticationProvider + * functionality. + * + * @author James Muehlner + * @author Michael Jumper + */ +public class PostgreSQLAuthenticationProvider implements AuthenticationProvider { + + /** + * Injector which will manage the object graph of this authentication + * provider. + */ + private final Injector injector; + + /** + * Returns the appropriate socket service class given the Guacamole + * environment. The class is chosen based on configuration options that + * dictate concurrent usage policy. + * + * @param environment + * The environment of the Guacamole server. + * + * @return + * The socket service class that matches the concurrent usage policy + * options set in the Guacamole environment. + * + * @throws GuacamoleException + * If an error occurs while reading the configuration options. + */ + private Class + getSocketServiceClass(Environment environment) + throws GuacamoleException { + + // Read concurrency-related properties + boolean disallowSimultaneous = environment.getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_DISALLOW_SIMULTANEOUS_CONNECTIONS, false); + boolean disallowDuplicate = environment.getProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_DISALLOW_DUPLICATE_CONNECTIONS, true); + + if (disallowSimultaneous) { + + // Connections may not be used concurrently + if (disallowDuplicate) + return SingleSeatGuacamoleSocketService.class; + + // Connections are reserved for a single user when in use + else + return BalancedGuacamoleSocketService.class; + + } + + else { + + // Connections may be used concurrently, but only once per user + if (disallowDuplicate) + return MultiseatGuacamoleSocketService.class; + + // Connection use is not restricted + else + return UnrestrictedGuacamoleSocketService.class; + + } + + } + + /** + * Creates a new PostgreSQLAuthenticationProvider that reads and writes + * authentication data to a PostgreSQL database defined by properties in + * guacamole.properties. + * + * @throws GuacamoleException + * If a required property is missing, or an error occurs while parsing + * a property. + */ + public PostgreSQLAuthenticationProvider() throws GuacamoleException { + + // Get local environment + Environment environment = new LocalEnvironment(); + + // Set up Guice injector. + injector = Guice.createInjector( + + // Configure PostgreSQL-specific authentication + new PostgreSQLAuthenticationProviderModule(environment), + + // Configure JDBC authentication core + new JDBCAuthenticationProviderModule(environment, getSocketServiceClass(environment)) + + ); + + } + + @Override + public UserContext getUserContext(Credentials credentials) + throws GuacamoleException { + + // Create UserContext based on credentials, if valid + UserContextService userContextService = injector.getInstance(UserContextService.class); + return userContextService.getUserContext(credentials); + + } + + @Override + public UserContext updateUserContext(UserContext context, + Credentials credentials) throws GuacamoleException { + + // No need to update the context + return context; + + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java new file mode 100644 index 000000000..2decdf9a6 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLAuthenticationProviderModule.java @@ -0,0 +1,99 @@ +/* + * 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.auth.postgresql; + +import com.google.inject.Binder; +import com.google.inject.Module; +import com.google.inject.name.Names; +import java.util.Properties; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.environment.Environment; +import org.mybatis.guice.datasource.helper.JdbcHelper; + +/** + * Guice module which configures PostgreSQL-specific injections. + * + * @author James Muehlner + * @author Michael Jumper + */ +public class PostgreSQLAuthenticationProviderModule implements Module { + + /** + * MyBatis-specific configuration properties. + */ + private final Properties myBatisProperties = new Properties(); + + /** + * PostgreSQL-specific driver configuration properties. + */ + private final Properties driverProperties = new Properties(); + + /** + * Creates a new PostgreSQL authentication provider module that configures + * driver and MyBatis properties using the given environment. + * + * @param environment + * The environment to use when configuring MyBatis and the underlying + * JDBC driver. + * + * @throws GuacamoleException + * If a required property is missing, or an error occurs while parsing + * a property. + */ + public PostgreSQLAuthenticationProviderModule(Environment environment) + throws GuacamoleException { + + // Set the PostgreSQL-specific properties for MyBatis. + myBatisProperties.setProperty("mybatis.environment.id", "guacamole"); + myBatisProperties.setProperty("JDBC.host", environment.getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_HOSTNAME)); + myBatisProperties.setProperty("JDBC.port", String.valueOf(environment.getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_PORT))); + myBatisProperties.setProperty("JDBC.schema", environment.getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_DATABASE)); + myBatisProperties.setProperty("JDBC.username", environment.getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_USERNAME)); + myBatisProperties.setProperty("JDBC.password", environment.getRequiredProperty(PostgreSQLGuacamoleProperties.POSTGRESQL_PASSWORD)); + myBatisProperties.setProperty("JDBC.autoCommit", "false"); + myBatisProperties.setProperty("mybatis.pooled.pingEnabled", "true"); + myBatisProperties.setProperty("mybatis.pooled.pingQuery", "SELECT 1"); + + // Use UTF-8 in database + driverProperties.setProperty("characterEncoding","UTF-8"); + + + } + + @Override + public void configure(Binder binder) { + + // Bind PostgreSQL-specific properties + JdbcHelper.PostgreSQL.configure(binder); + + // Bind MyBatis properties + Names.bindProperties(binder, myBatisProperties); + + // Bing JDBC driver properties + binder.bind(Properties.class) + .annotatedWith(Names.named("JDBC.driverProperties")) + .toInstance(driverProperties); + + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLGuacamoleProperties.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLGuacamoleProperties.java new file mode 100644 index 000000000..abb5a1249 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/PostgreSQLGuacamoleProperties.java @@ -0,0 +1,127 @@ +/* + * 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.auth.postgresql; + +import org.glyptodon.guacamole.properties.BooleanGuacamoleProperty; +import org.glyptodon.guacamole.properties.IntegerGuacamoleProperty; +import org.glyptodon.guacamole.properties.StringGuacamoleProperty; + +/** + * Properties used by the PostgreSQL Authentication plugin. + * + * @author James Muehlner + * @author Michael Jumper + */ +public class PostgreSQLGuacamoleProperties { + + /** + * This class should not be instantiated. + */ + private PostgreSQLGuacamoleProperties() {} + + /** + * The URL of the PostgreSQL server hosting the Guacamole authentication tables. + */ + public static final StringGuacamoleProperty POSTGRESQL_HOSTNAME = + new StringGuacamoleProperty() { + + @Override + public String getName() { return "postgresql-hostname"; } + + }; + + /** + * The port of the PostgreSQL server hosting the Guacamole authentication + * tables. + */ + public static final IntegerGuacamoleProperty POSTGRESQL_PORT = + new IntegerGuacamoleProperty() { + + @Override + public String getName() { return "postgresql-port"; } + + }; + + /** + * The name of the PostgreSQL database containing the Guacamole + * authentication tables. + */ + public static final StringGuacamoleProperty POSTGRESQL_DATABASE = + new StringGuacamoleProperty() { + + @Override + public String getName() { return "postgresql-database"; } + + }; + + /** + * The username used to authenticate to the PostgreSQL database containing + * the Guacamole authentication tables. + */ + public static final StringGuacamoleProperty POSTGRESQL_USERNAME = + new StringGuacamoleProperty() { + + @Override + public String getName() { return "postgresql-username"; } + + }; + + /** + * The password used to authenticate to the PostgreSQL database containing + * the Guacamole authentication tables. + */ + public static final StringGuacamoleProperty POSTGRESQL_PASSWORD = + new StringGuacamoleProperty() { + + @Override + public String getName() { return "postgresql-password"; } + + }; + + /** + * Whether or not multiple users accessing the same connection at the same + * time should be disallowed. + */ + public static final BooleanGuacamoleProperty + POSTGRESQL_DISALLOW_SIMULTANEOUS_CONNECTIONS = + new BooleanGuacamoleProperty() { + + @Override + public String getName() { return "postgresql-disallow-simultaneous-connections"; } + + }; + + /** + * Whether or not the same user accessing the same connection or connection + * group at the same time should be disallowed. + */ + public static final BooleanGuacamoleProperty + POSTGRESQL_DISALLOW_DUPLICATE_CONNECTIONS = + new BooleanGuacamoleProperty() { + + @Override + public String getName() { return "postgresql-disallow-duplicate-connections"; } + + }; + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/package-info.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/package-info.java new file mode 100644 index 000000000..1a939e1a6 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/java/org/glyptodon/guacamole/auth/postgresql/package-info.java @@ -0,0 +1,26 @@ +/* + * 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. + */ + +/** + * The PostgreSQL authentication provider. + */ +package org.glyptodon.guacamole.auth.postgresql; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionMapper.xml new file mode 100644 index 000000000..2211da069 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionMapper.xml @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM guacamole_connection + WHERE connection_id = #{identifier,jdbcType=VARCHAR} + + + + + + INSERT INTO guacamole_connection ( + connection_name, + parent_id, + protocol + ) + VALUES ( + #{object.name,jdbcType=VARCHAR}, + #{object.parentIdentifier,jdbcType=VARCHAR}, + #{object.protocol,jdbcType=VARCHAR} + ) + + + + + + UPDATE guacamole_connection + SET connection_name = #{object.name,jdbcType=VARCHAR}, + parent_id = #{object.parentIdentifier,jdbcType=VARCHAR}, + protocol = #{object.protocol,jdbcType=VARCHAR} + WHERE connection_id = #{object.objectID,jdbcType=INTEGER} + + + \ No newline at end of file diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml new file mode 100644 index 000000000..b5775f607 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + INSERT INTO guacamole_connection_history ( + connection_id, + user_id, + start_date, + end_date + ) + VALUES ( + #{record.connectionIdentifier,jdbcType=VARCHAR}, + #{record.userID,jdbcType=INTEGER}, + #{record.startDate,jdbcType=TIMESTAMP}, + #{record.endDate,jdbcType=TIMESTAMP} + ) + + + + \ No newline at end of file diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ParameterMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ParameterMapper.xml new file mode 100644 index 000000000..ccd386c14 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ParameterMapper.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + DELETE FROM guacamole_connection_parameter + WHERE connection_id = #{identifier,jdbcType=VARCHAR} + + + + + + INSERT INTO guacamole_connection_parameter ( + connection_id, + parameter_name, + parameter_value + ) + VALUES + + (#{parameter.connectionIdentifier,jdbcType=VARCHAR}, + #{parameter.name,jdbcType=VARCHAR}, + #{parameter.value,jdbcType=VARCHAR}) + + + + + + \ No newline at end of file diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml new file mode 100644 index 000000000..4eb20da1c --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM guacamole_connection_group + WHERE connection_group_id = #{identifier,jdbcType=VARCHAR} + + + + + + INSERT INTO guacamole_connection_group ( + connection_group_name, + parent_id, + type + ) + VALUES ( + #{object.name,jdbcType=VARCHAR}, + #{object.parentIdentifier,jdbcType=VARCHAR}, + #{object.type,jdbcType=VARCHAR} + ) + + + + + + UPDATE guacamole_connection_group + SET connection_group_name = #{object.name,jdbcType=VARCHAR}, + parent_id = #{object.parentIdentifier,jdbcType=VARCHAR}, + type = #{object.type,jdbcType=VARCHAR} + WHERE connection_group_id = #{object.objectID,jdbcType=INTEGER} + + + \ No newline at end of file diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml new file mode 100644 index 000000000..40ada12a5 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM guacamole_connection_group_permission + WHERE (user_id, permission, connection_group_id) IN + + (#{permission.userID,jdbcType=INTEGER}, + #{permission.type,jdbcType=VARCHAR}, + #{permission.objectIdentifier,jdbcType=VARCHAR}) + + + + + + + + INSERT IGNORE INTO guacamole_connection_group_permission ( + user_id, + permission, + connection_group_id + ) + VALUES + + (#{permission.userID,jdbcType=INTEGER}, + #{permission.type,jdbcType=VARCHAR}, + #{permission.objectIdentifier,jdbcType=VARCHAR}) + + + + + \ No newline at end of file diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml new file mode 100644 index 000000000..9935f3cfd --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM guacamole_connection_permission + WHERE (user_id, permission, connection_id) IN + + (#{permission.userID,jdbcType=INTEGER}, + #{permission.type,jdbcType=VARCHAR}, + #{permission.objectIdentifier,jdbcType=VARCHAR}) + + + + + + + + INSERT IGNORE INTO guacamole_connection_permission ( + user_id, + permission, + connection_id + ) + VALUES + + (#{permission.userID,jdbcType=INTEGER}, + #{permission.type,jdbcType=VARCHAR}, + #{permission.objectIdentifier,jdbcType=VARCHAR}) + + + + + \ No newline at end of file diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml new file mode 100644 index 000000000..55eacd072 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM guacamole_system_permission + WHERE (user_id, permission) IN + + (#{permission.userID,jdbcType=INTEGER}, + #{permission.type,jdbcType=VARCHAR}) + + + + + + + + INSERT IGNORE INTO guacamole_system_permission ( + user_id, + permission + ) + VALUES + + (#{permission.userID,jdbcType=INTEGER}, + #{permission.type,jdbcType=VARCHAR}) + + + + + \ No newline at end of file diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml new file mode 100644 index 000000000..038bb814f --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM guacamole_user_permission + USING guacamole_user_permission + JOIN guacamole_user affected ON guacamole_user_permission.affected_user_id = affected.user_id + WHERE + (guacamole_user_permission.user_id, permission, affected.username) IN + + (#{permission.userID,jdbcType=INTEGER}, + #{permission.type,jdbcType=VARCHAR}, + #{permission.objectIdentifier,jdbcType=VARCHAR}) + + + + + + + + INSERT IGNORE INTO guacamole_user_permission ( + user_id, + permission, + affected_user_id + ) + SELECT permissions.user_id, permissions.permission, guacamole_user.user_id FROM + + SELECT #{permission.userID,jdbcType=INTEGER} AS user_id, + #{permission.type,jdbcType=VARCHAR} AS permission, + #{permission.objectIdentifier,jdbcType=VARCHAR} AS username + + AS permissions + JOIN guacamole_user ON guacamole_user.username = permissions.username; + + + + \ No newline at end of file diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/user/UserMapper.xml new file mode 100644 index 000000000..5170d43ee --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/user/UserMapper.xml @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DELETE FROM guacamole_user + WHERE username = #{identifier,jdbcType=VARCHAR} + + + + + + INSERT INTO guacamole_user ( + username, + password_hash, + password_salt + ) + VALUES ( + #{object.identifier,jdbcType=VARCHAR}, + #{object.passwordHash,jdbcType=BINARY}, + #{object.passwordSalt,jdbcType=BINARY} + ) + + + + + + UPDATE guacamole_user + SET password_hash = #{object.passwordHash,jdbcType=BINARY}, + password_salt = #{object.passwordSalt,jdbcType=BINARY} + WHERE user_id = #{object.objectID,jdbcType=VARCHAR} + + + diff --git a/extensions/guacamole-auth-jdbc/pom.xml b/extensions/guacamole-auth-jdbc/pom.xml index c6c622994..49fb5c124 100644 --- a/extensions/guacamole-auth-jdbc/pom.xml +++ b/extensions/guacamole-auth-jdbc/pom.xml @@ -20,8 +20,9 @@ modules/guacamole-auth-jdbc-base - + modules/guacamole-auth-jdbc-mysql + modules/guacamole-auth-jdbc-postgresql From 4e08c10f9451abf422f0459a5eb48a5f12abdc28 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 2 Mar 2015 15:15:38 -0800 Subject: [PATCH 07/23] GUAC-1103: Translate copied MySQL schema to PostgreSQL. --- .../schema/001-create-schema.sql | 271 ++++++++++-------- .../schema/002-create-admin-user.sql | 6 +- 2 files changed, 161 insertions(+), 116 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql index 5c23bfc90..a52fefecc 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql @@ -1,5 +1,5 @@ -- --- Copyright (C) 2013 Glyptodon LLC +-- 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 @@ -20,26 +20,62 @@ -- THE SOFTWARE. -- +-- +-- Connection group types +-- + +CREATE TYPE guacamole_connection_group_type AS ENUM( + 'ORGANIZATIONAL', + 'BALANCING' +); + +-- +-- Object permission types +-- + +CREATE TYPE guacamole_object_permission_type AS ENUM( + 'READ', + 'UPDATE', + 'DELETE', + 'ADMINISTER' +); + +-- +-- System permission types +-- + +CREATE TYPE guacamole_system_permission_type AS ENUM( + 'CREATE_CONNECTION', + 'CREATE_CONNECTION_GROUP', + 'CREATE_USER', + 'ADMINISTER' +); + -- -- Table of connection groups. Each connection group has a name. -- -CREATE TABLE `guacamole_connection_group` ( +CREATE TABLE guacamole_connection_group ( - `connection_group_id` int(11) NOT NULL AUTO_INCREMENT, - `parent_id` int(11), - `connection_group_name` varchar(128) NOT NULL, - `type` enum('ORGANIZATIONAL', - 'BALANCING') NOT NULL DEFAULT 'ORGANIZATIONAL', + connection_group_id serial NOT NULL, + parent_id integer, + connection_group_name varchar(128) NOT NULL, + type guacamole_connection_group_type + NOT NULL DEFAULT 'ORGANIZATIONAL', - PRIMARY KEY (`connection_group_id`), - UNIQUE KEY `connection_group_name_parent` (`connection_group_name`, `parent_id`), + PRIMARY KEY (connection_group_id), - CONSTRAINT `guacamole_connection_group_ibfk_1` - FOREIGN KEY (`parent_id`) - REFERENCES `guacamole_connection_group` (`connection_group_id`) ON DELETE CASCADE + CONSTRAINT connection_group_name_parent + UNIQUE (connection_group_name, parent_id), -) ENGINE=InnoDB DEFAULT CHARSET=utf8; + CONSTRAINT guacamole_connection_group_ibfk_1 + FOREIGN KEY (parent_id) + REFERENCES guacamole_connection_group (connection_group_id) + ON DELETE CASCADE + +); + +CREATE INDEX ON guacamole_connection_group(parent_id); -- -- Table of connections. Each connection has a name, protocol, and @@ -47,156 +83,164 @@ CREATE TABLE `guacamole_connection_group` ( -- A connection may belong to a connection group. -- -CREATE TABLE `guacamole_connection` ( +CREATE TABLE guacamole_connection ( - `connection_id` int(11) NOT NULL AUTO_INCREMENT, - `connection_name` varchar(128) NOT NULL, - `parent_id` int(11), - `protocol` varchar(32) NOT NULL, + connection_id serial NOT NULL, + connection_name varchar(128) NOT NULL, + parent_id integer, + protocol varchar(32) NOT NULL, - PRIMARY KEY (`connection_id`), - UNIQUE KEY `connection_name_parent` (`connection_name`, `parent_id`), + PRIMARY KEY (connection_id), - CONSTRAINT `guacamole_connection_ibfk_1` - FOREIGN KEY (`parent_id`) - REFERENCES `guacamole_connection_group` (`connection_group_id`) ON DELETE CASCADE + CONSTRAINT connection_name_parent + UNIQUE (connection_name, parent_id), -) ENGINE=InnoDB DEFAULT CHARSET=utf8; + CONSTRAINT guacamole_connection_ibfk_1 + FOREIGN KEY (parent_id) + REFERENCES guacamole_connection_group (connection_group_id) + ON DELETE CASCADE + +); + +CREATE INDEX ON guacamole_connection(parent_id); -- -- Table of users. Each user has a unique username and a hashed password -- with corresponding salt. -- -CREATE TABLE `guacamole_user` ( +CREATE TABLE guacamole_user ( - `user_id` int(11) NOT NULL AUTO_INCREMENT, - `username` varchar(128) NOT NULL, - `password_hash` binary(32) NOT NULL, - `password_salt` binary(32) NOT NULL, + user_id serial NOT NULL, + username varchar(128) NOT NULL, + password_hash bytea NOT NULL, + password_salt bytea NOT NULL, - PRIMARY KEY (`user_id`), - UNIQUE KEY `username` (`username`) + PRIMARY KEY (user_id), -) ENGINE=InnoDB DEFAULT CHARSET=utf8; + CONSTRAINT username + UNIQUE (username) + +); -- -- Table of connection parameters. Each parameter is simply a name/value pair -- associated with a connection. -- -CREATE TABLE `guacamole_connection_parameter` ( +CREATE TABLE guacamole_connection_parameter ( - `connection_id` int(11) NOT NULL, - `parameter_name` varchar(128) NOT NULL, - `parameter_value` varchar(4096) NOT NULL, + connection_id integer NOT NULL, + parameter_name varchar(128) NOT NULL, + parameter_value varchar(4096) NOT NULL, - PRIMARY KEY (`connection_id`,`parameter_name`), + PRIMARY KEY (connection_id,parameter_name), - CONSTRAINT `guacamole_connection_parameter_ibfk_1` - FOREIGN KEY (`connection_id`) - REFERENCES `guacamole_connection` (`connection_id`) ON DELETE CASCADE + CONSTRAINT guacamole_connection_parameter_ibfk_1 + FOREIGN KEY (connection_id) + REFERENCES guacamole_connection (connection_id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +); + +CREATE INDEX ON guacamole_connection_parameter(connection_id); -- -- Table of connection permissions. Each connection permission grants a user -- specific access to a connection. -- -CREATE TABLE `guacamole_connection_permission` ( +CREATE TABLE guacamole_connection_permission ( - `user_id` int(11) NOT NULL, - `connection_id` int(11) NOT NULL, - `permission` enum('READ', - 'UPDATE', - 'DELETE', - 'ADMINISTER') NOT NULL, + user_id integer NOT NULL, + connection_id integer NOT NULL, + permission guacamole_object_permission_type NOT NULL, - PRIMARY KEY (`user_id`,`connection_id`,`permission`), + PRIMARY KEY (user_id,connection_id,permission), - CONSTRAINT `guacamole_connection_permission_ibfk_1` - FOREIGN KEY (`connection_id`) - REFERENCES `guacamole_connection` (`connection_id`) ON DELETE CASCADE, + CONSTRAINT guacamole_connection_permission_ibfk_1 + FOREIGN KEY (connection_id) + REFERENCES guacamole_connection (connection_id) ON DELETE CASCADE, - CONSTRAINT `guacamole_connection_permission_ibfk_2` - FOREIGN KEY (`user_id`) - REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE + CONSTRAINT guacamole_connection_permission_ibfk_2 + FOREIGN KEY (user_id) + REFERENCES guacamole_user (user_id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +); + +CREATE INDEX ON guacamole_connection_permission(connection_id); +CREATE INDEX ON guacamole_connection_permission(user_id); -- -- Table of connection group permissions. Each group permission grants a user -- specific access to a connection group. -- -CREATE TABLE `guacamole_connection_group_permission` ( +CREATE TABLE guacamole_connection_group_permission ( - `user_id` int(11) NOT NULL, - `connection_group_id` int(11) NOT NULL, - `permission` enum('READ', - 'UPDATE', - 'DELETE', - 'ADMINISTER') NOT NULL, + user_id integer NOT NULL, + connection_group_id integer NOT NULL, + permission guacamole_object_permission_type NOT NULL, - PRIMARY KEY (`user_id`,`connection_group_id`,`permission`), + PRIMARY KEY (user_id,connection_group_id,permission), - CONSTRAINT `guacamole_connection_group_permission_ibfk_1` - FOREIGN KEY (`connection_group_id`) - REFERENCES `guacamole_connection_group` (`connection_group_id`) ON DELETE CASCADE, + CONSTRAINT guacamole_connection_group_permission_ibfk_1 + FOREIGN KEY (connection_group_id) + REFERENCES guacamole_connection_group (connection_group_id) ON DELETE CASCADE, - CONSTRAINT `guacamole_connection_group_permission_ibfk_2` - FOREIGN KEY (`user_id`) - REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE + CONSTRAINT guacamole_connection_group_permission_ibfk_2 + FOREIGN KEY (user_id) + REFERENCES guacamole_user (user_id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +); + +CREATE INDEX ON guacamole_connection_group_permission(connection_group_id); +CREATE INDEX ON guacamole_connection_group_permission(user_id); -- -- Table of system permissions. Each system permission grants a user a -- system-level privilege of some kind. -- -CREATE TABLE `guacamole_system_permission` ( +CREATE TABLE guacamole_system_permission ( - `user_id` int(11) NOT NULL, - `permission` enum('CREATE_CONNECTION', - 'CREATE_CONNECTION_GROUP', - 'CREATE_USER', - 'ADMINISTER') NOT NULL, + user_id integer NOT NULL, + permission guacamole_system_permission_type NOT NULL, - PRIMARY KEY (`user_id`,`permission`), + PRIMARY KEY (user_id,permission), - CONSTRAINT `guacamole_system_permission_ibfk_1` - FOREIGN KEY (`user_id`) - REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE + CONSTRAINT guacamole_system_permission_ibfk_1 + FOREIGN KEY (user_id) + REFERENCES guacamole_user (user_id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +); + +CREATE INDEX ON guacamole_system_permission(user_id); -- -- Table of user permissions. Each user permission grants a user access to -- another user (the "affected" user) for a specific type of operation. -- -CREATE TABLE `guacamole_user_permission` ( +CREATE TABLE guacamole_user_permission ( - `user_id` int(11) NOT NULL, - `affected_user_id` int(11) NOT NULL, - `permission` enum('READ', - 'UPDATE', - 'DELETE', - 'ADMINISTER') NOT NULL, + user_id integer NOT NULL, + affected_user_id integer NOT NULL, + permission guacamole_object_permission_type NOT NULL, - PRIMARY KEY (`user_id`,`affected_user_id`,`permission`), + PRIMARY KEY (user_id,affected_user_id,permission), - CONSTRAINT `guacamole_user_permission_ibfk_1` - FOREIGN KEY (`affected_user_id`) - REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE, + CONSTRAINT guacamole_user_permission_ibfk_1 + FOREIGN KEY (affected_user_id) + REFERENCES guacamole_user (user_id) ON DELETE CASCADE, - CONSTRAINT `guacamole_user_permission_ibfk_2` - FOREIGN KEY (`user_id`) - REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE + CONSTRAINT guacamole_user_permission_ibfk_2 + FOREIGN KEY (user_id) + REFERENCES guacamole_user (user_id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +); + +CREATE INDEX ON guacamole_user_permission(affected_user_id); +CREATE INDEX ON guacamole_user_permission(user_id); -- -- Table of connection history records. Each record defines a specific user's @@ -204,25 +248,26 @@ CREATE TABLE `guacamole_user_permission` ( -- (if any). -- -CREATE TABLE `guacamole_connection_history` ( +CREATE TABLE guacamole_connection_history ( - `history_id` int(11) NOT NULL AUTO_INCREMENT, - `user_id` int(11) NOT NULL, - `connection_id` int(11) NOT NULL, - `start_date` datetime NOT NULL, - `end_date` datetime DEFAULT NULL, + history_id serial NOT NULL, + user_id integer NOT NULL, + connection_id integer NOT NULL, + start_date timestamptz NOT NULL, + end_date timestamptz DEFAULT NULL, - PRIMARY KEY (`history_id`), - KEY `user_id` (`user_id`), - KEY `connection_id` (`connection_id`), + PRIMARY KEY (history_id), - CONSTRAINT `guacamole_connection_history_ibfk_1` - FOREIGN KEY (`user_id`) - REFERENCES `guacamole_user` (`user_id`) ON DELETE CASCADE, + CONSTRAINT guacamole_connection_history_ibfk_1 + FOREIGN KEY (user_id) + REFERENCES guacamole_user (user_id) ON DELETE CASCADE, - CONSTRAINT `guacamole_connection_history_ibfk_2` - FOREIGN KEY (`connection_id`) - REFERENCES `guacamole_connection` (`connection_id`) ON DELETE CASCADE + CONSTRAINT guacamole_connection_history_ibfk_2 + FOREIGN KEY (connection_id) + REFERENCES guacamole_connection (connection_id) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; +); + +CREATE INDEX ON guacamole_connection_history(user_id); +CREATE INDEX ON guacamole_connection_history(connection_id); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql index 997a48841..9b912548d 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql @@ -1,5 +1,5 @@ -- --- Copyright (C) 2013 Glyptodon LLC +-- 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 @@ -22,8 +22,8 @@ -- Create default user "guacadmin" with password "guacadmin" insert into guacamole_user values(1, 'guacadmin', - x'CA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960', -- 'guacadmin' - x'FE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264'); + E'\\xCA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960', -- 'guacadmin' + E'\\xFE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264'); -- Grant this user create permissions insert into guacamole_system_permission values(1, 'CREATE_CONNECTION'); From 06a7ab4cec58e591b27ef1d782a7402a63dca0a6 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 2 Mar 2015 17:39:43 -0800 Subject: [PATCH 08/23] GUAC-1103: Explicitly cast permission types. --- .../permission/ConnectionGroupPermissionMapper.xml | 8 ++++---- .../jdbc/permission/ConnectionPermissionMapper.xml | 8 ++++---- .../auth/jdbc/permission/SystemPermissionMapper.xml | 6 +++--- .../auth/jdbc/permission/UserPermissionMapper.xml | 12 ++++++------ 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml index 40ada12a5..1d10233a9 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml @@ -61,7 +61,7 @@ JOIN guacamole_user ON guacamole_connection_group_permission.user_id = guacamole_user.user_id WHERE guacamole_connection_group_permission.user_id = #{user.objectID,jdbcType=INTEGER} - AND permission = #{type,jdbcType=VARCHAR} + AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type AND connection_group_id = #{identifier,jdbcType=VARCHAR} @@ -81,7 +81,7 @@ AND permission IN - #{permission,jdbcType=VARCHAR} + #{permission,jdbcType=VARCHAR}::guacamole_object_permission_type @@ -94,7 +94,7 @@ (#{permission.userID,jdbcType=INTEGER}, - #{permission.type,jdbcType=VARCHAR}, + #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, #{permission.objectIdentifier,jdbcType=VARCHAR}) @@ -111,7 +111,7 @@ VALUES (#{permission.userID,jdbcType=INTEGER}, - #{permission.type,jdbcType=VARCHAR}, + #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, #{permission.objectIdentifier,jdbcType=VARCHAR}) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml index 9935f3cfd..4bd33de78 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml @@ -61,7 +61,7 @@ JOIN guacamole_user ON guacamole_connection_permission.user_id = guacamole_user.user_id WHERE guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER} - AND permission = #{type,jdbcType=VARCHAR} + AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type AND connection_id = #{identifier,jdbcType=VARCHAR} @@ -81,7 +81,7 @@ AND permission IN - #{permission,jdbcType=VARCHAR} + #{permission,jdbcType=VARCHAR}::guacamole_object_permission_type @@ -94,7 +94,7 @@ (#{permission.userID,jdbcType=INTEGER}, - #{permission.type,jdbcType=VARCHAR}, + #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, #{permission.objectIdentifier,jdbcType=VARCHAR}) @@ -111,7 +111,7 @@ VALUES (#{permission.userID,jdbcType=INTEGER}, - #{permission.type,jdbcType=VARCHAR}, + #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, #{permission.objectIdentifier,jdbcType=VARCHAR}) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml index 55eacd072..d472dc2ba 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml @@ -58,7 +58,7 @@ JOIN guacamole_user ON guacamole_system_permission.user_id = guacamole_user.user_id WHERE guacamole_system_permission.user_id = #{user.objectID,jdbcType=INTEGER} - AND permission = #{type,jdbcType=VARCHAR} + AND permission = #{type,jdbcType=VARCHAR}::guacamole_system_permission_type @@ -70,7 +70,7 @@ (#{permission.userID,jdbcType=INTEGER}, - #{permission.type,jdbcType=VARCHAR}) + #{permission.type,jdbcType=VARCHAR}::guacamole_system_permission_type) @@ -85,7 +85,7 @@ VALUES (#{permission.userID,jdbcType=INTEGER}, - #{permission.type,jdbcType=VARCHAR}) + #{permission.type,jdbcType=VARCHAR}::guacamole_system_permission_type) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml index 038bb814f..b995dae19 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml @@ -63,7 +63,7 @@ JOIN guacamole_user affected ON guacamole_user_permission.affected_user_id = affected.user_id WHERE guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} - AND permission = #{type,jdbcType=VARCHAR} + AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type AND affected.username = #{identifier,jdbcType=VARCHAR} @@ -84,7 +84,7 @@ AND permission IN - #{permission,jdbcType=VARCHAR} + #{permission,jdbcType=VARCHAR}::guacamole_object_permission_type @@ -100,7 +100,7 @@ (#{permission.userID,jdbcType=INTEGER}, - #{permission.type,jdbcType=VARCHAR}, + #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, #{permission.objectIdentifier,jdbcType=VARCHAR}) @@ -117,9 +117,9 @@ SELECT permissions.user_id, permissions.permission, guacamole_user.user_id FROM - SELECT #{permission.userID,jdbcType=INTEGER} AS user_id, - #{permission.type,jdbcType=VARCHAR} AS permission, - #{permission.objectIdentifier,jdbcType=VARCHAR} AS username + SELECT #{permission.userID,jdbcType=INTEGER} AS user_id, + #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type AS permission, + #{permission.objectIdentifier,jdbcType=VARCHAR} AS username AS permissions JOIN guacamole_user ON guacamole_user.username = permissions.username; From 4a0213397b4609010c2dc08e40f562c1123d4953 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 2 Mar 2015 18:00:12 -0800 Subject: [PATCH 09/23] GUAC-1103: Convert string identifiers to integer where known to be integers. --- .../auth/jdbc/connection/ConnectionMapper.xml | 16 ++++++++-------- .../jdbc/connection/ConnectionRecordMapper.xml | 4 ++-- .../auth/jdbc/connection/ParameterMapper.xml | 6 +++--- .../connectiongroup/ConnectionGroupMapper.xml | 16 ++++++++-------- .../ConnectionGroupPermissionMapper.xml | 8 ++++---- .../permission/ConnectionPermissionMapper.xml | 8 ++++---- .../jdbc/permission/UserPermissionMapper.xml | 8 ++++---- 7 files changed, 33 insertions(+), 33 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionMapper.xml index 2211da069..249ca6e78 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionMapper.xml @@ -54,7 +54,7 @@ SELECT connection_id FROM guacamole_connection WHERE - parent_id = #{parentIdentifier,jdbcType=VARCHAR} + parent_id = #{parentIdentifier,jdbcType=INTEGER} parent_id IS NULL @@ -64,7 +64,7 @@ FROM guacamole_connection JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection.connection_id WHERE - parent_id = #{parentIdentifier,jdbcType=VARCHAR} + parent_id = #{parentIdentifier,jdbcType=INTEGER} parent_id IS NULL AND user_id = #{user.objectID,jdbcType=INTEGER} AND permission = 'READ' @@ -82,7 +82,7 @@ WHERE connection_id IN - #{identifier,jdbcType=VARCHAR} + #{identifier,jdbcType=INTEGER} @@ -100,7 +100,7 @@ WHERE guacamole_connection.connection_id IN - #{identifier,jdbcType=VARCHAR} + #{identifier,jdbcType=INTEGER} AND user_id = #{user.objectID,jdbcType=INTEGER} AND permission = 'READ' @@ -117,7 +117,7 @@ protocol FROM guacamole_connection WHERE - parent_id = #{parentIdentifier,jdbcType=VARCHAR} + parent_id = #{parentIdentifier,jdbcType=INTEGER} parent_id IS NULL AND connection_name = #{name,jdbcType=VARCHAR} @@ -126,7 +126,7 @@ DELETE FROM guacamole_connection - WHERE connection_id = #{identifier,jdbcType=VARCHAR} + WHERE connection_id = #{identifier,jdbcType=INTEGER} @@ -140,7 +140,7 @@ ) VALUES ( #{object.name,jdbcType=VARCHAR}, - #{object.parentIdentifier,jdbcType=VARCHAR}, + #{object.parentIdentifier,jdbcType=INTEGER}, #{object.protocol,jdbcType=VARCHAR} ) @@ -150,7 +150,7 @@ UPDATE guacamole_connection SET connection_name = #{object.name,jdbcType=VARCHAR}, - parent_id = #{object.parentIdentifier,jdbcType=VARCHAR}, + parent_id = #{object.parentIdentifier,jdbcType=INTEGER}, protocol = #{object.protocol,jdbcType=VARCHAR} WHERE connection_id = #{object.objectID,jdbcType=INTEGER} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml index b5775f607..41601b731 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml @@ -47,7 +47,7 @@ FROM guacamole_connection_history JOIN guacamole_user ON guacamole_connection_history.user_id = guacamole_user.user_id WHERE - connection_id = #{identifier,jdbcType=VARCHAR} + connection_id = #{identifier,jdbcType=INTEGER} ORDER BY start_date DESC, end_date DESC @@ -64,7 +64,7 @@ end_date ) VALUES ( - #{record.connectionIdentifier,jdbcType=VARCHAR}, + #{record.connectionIdentifier,jdbcType=INTEGER}, #{record.userID,jdbcType=INTEGER}, #{record.startDate,jdbcType=TIMESTAMP}, #{record.endDate,jdbcType=TIMESTAMP} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ParameterMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ParameterMapper.xml index ccd386c14..55212d026 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ParameterMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ParameterMapper.xml @@ -41,13 +41,13 @@ parameter_value FROM guacamole_connection_parameter WHERE - connection_id = #{identifier,jdbcType=VARCHAR} + connection_id = #{identifier,jdbcType=INTEGER} DELETE FROM guacamole_connection_parameter - WHERE connection_id = #{identifier,jdbcType=VARCHAR} + WHERE connection_id = #{identifier,jdbcType=INTEGER} @@ -60,7 +60,7 @@ ) VALUES - (#{parameter.connectionIdentifier,jdbcType=VARCHAR}, + (#{parameter.connectionIdentifier,jdbcType=INTEGER}, #{parameter.name,jdbcType=VARCHAR}, #{parameter.value,jdbcType=VARCHAR}) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml index 4eb20da1c..63bd1abae 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml @@ -55,7 +55,7 @@ SELECT connection_group_id FROM guacamole_connection_group WHERE - parent_id = #{parentIdentifier,jdbcType=VARCHAR} + parent_id = #{parentIdentifier,jdbcType=INTEGER} parent_id IS NULL @@ -65,7 +65,7 @@ FROM guacamole_connection_group JOIN guacamole_connection_group_permission ON guacamole_connection_group_permission.connection_group_id = guacamole_connection_group.connection_group_id WHERE - parent_id = #{parentIdentifier,jdbcType=VARCHAR} + parent_id = #{parentIdentifier,jdbcType=INTEGER} parent_id IS NULL AND user_id = #{user.objectID,jdbcType=INTEGER} AND permission = 'READ' @@ -83,7 +83,7 @@ WHERE connection_group_id IN - #{identifier,jdbcType=VARCHAR} + #{identifier,jdbcType=INTEGER} @@ -101,7 +101,7 @@ WHERE guacamole_connection_group.connection_group_id IN - #{identifier,jdbcType=VARCHAR} + #{identifier,jdbcType=INTEGER} AND user_id = #{user.objectID,jdbcType=INTEGER} AND permission = 'READ' @@ -118,7 +118,7 @@ type FROM guacamole_connection_group WHERE - parent_id = #{parentIdentifier,jdbcType=VARCHAR} + parent_id = #{parentIdentifier,jdbcType=INTEGER} parent_id IS NULL AND connection_group_name = #{name,jdbcType=VARCHAR} @@ -127,7 +127,7 @@ DELETE FROM guacamole_connection_group - WHERE connection_group_id = #{identifier,jdbcType=VARCHAR} + WHERE connection_group_id = #{identifier,jdbcType=INTEGER} @@ -141,7 +141,7 @@ ) VALUES ( #{object.name,jdbcType=VARCHAR}, - #{object.parentIdentifier,jdbcType=VARCHAR}, + #{object.parentIdentifier,jdbcType=INTEGER}, #{object.type,jdbcType=VARCHAR} ) @@ -151,7 +151,7 @@ UPDATE guacamole_connection_group SET connection_group_name = #{object.name,jdbcType=VARCHAR}, - parent_id = #{object.parentIdentifier,jdbcType=VARCHAR}, + parent_id = #{object.parentIdentifier,jdbcType=INTEGER}, type = #{object.type,jdbcType=VARCHAR} WHERE connection_group_id = #{object.objectID,jdbcType=INTEGER} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml index 1d10233a9..aad1dc09f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml @@ -62,7 +62,7 @@ WHERE guacamole_connection_group_permission.user_id = #{user.objectID,jdbcType=INTEGER} AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type - AND connection_group_id = #{identifier,jdbcType=VARCHAR} + AND connection_group_id = #{identifier,jdbcType=INTEGER} @@ -76,7 +76,7 @@ AND connection_group_id IN - #{identifier,jdbcType=VARCHAR} + #{identifier,jdbcType=INTEGER} AND permission IN (#{permission.userID,jdbcType=INTEGER}, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, - #{permission.objectIdentifier,jdbcType=VARCHAR}) + #{permission.objectIdentifier,jdbcType=INTEGER}::integer) @@ -112,7 +112,7 @@ (#{permission.userID,jdbcType=INTEGER}, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, - #{permission.objectIdentifier,jdbcType=VARCHAR}) + #{permission.objectIdentifier,jdbcType=INTEGER}) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml index 4bd33de78..f45778516 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml @@ -62,7 +62,7 @@ WHERE guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER} AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type - AND connection_id = #{identifier,jdbcType=VARCHAR} + AND connection_id = #{identifier,jdbcType=INTEGER} @@ -76,7 +76,7 @@ AND connection_id IN - #{identifier,jdbcType=VARCHAR} + #{identifier,jdbcType=INTEGER} AND permission IN (#{permission.userID,jdbcType=INTEGER}, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, - #{permission.objectIdentifier,jdbcType=VARCHAR}) + #{permission.objectIdentifier,jdbcType=INTEGER}) @@ -112,7 +112,7 @@ (#{permission.userID,jdbcType=INTEGER}, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, - #{permission.objectIdentifier,jdbcType=VARCHAR}) + #{permission.objectIdentifier,jdbcType=INTEGER}) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml index b995dae19..14ac6d9cb 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml @@ -64,7 +64,7 @@ WHERE guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type - AND affected.username = #{identifier,jdbcType=VARCHAR} + AND affected.username = #{identifier,jdbcType=INTEGER} @@ -79,7 +79,7 @@ AND username IN - #{identifier,jdbcType=VARCHAR} + #{identifier,jdbcType=INTEGER} AND permission IN (#{permission.userID,jdbcType=INTEGER}, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, - #{permission.objectIdentifier,jdbcType=VARCHAR}) + #{permission.objectIdentifier,jdbcType=INTEGER}) @@ -119,7 +119,7 @@ open="(" separator="UNION ALL" close=")"> SELECT #{permission.userID,jdbcType=INTEGER} AS user_id, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type AS permission, - #{permission.objectIdentifier,jdbcType=VARCHAR} AS username + #{permission.objectIdentifier,jdbcType=INTEGER} AS username AS permissions JOIN guacamole_user ON guacamole_user.username = permissions.username; From 233c12b2a15d4e0c98f13cc5cc6a0edc075f4c63 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 2 Mar 2015 19:46:33 -0800 Subject: [PATCH 10/23] GUAC-1103: Add PostgreSQL to .tar.gz assembly. --- .../guacamole-auth-jdbc/src/main/assembly/dist.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/extensions/guacamole-auth-jdbc/src/main/assembly/dist.xml b/extensions/guacamole-auth-jdbc/src/main/assembly/dist.xml index 2d20b63a0..a416ea191 100644 --- a/extensions/guacamole-auth-jdbc/src/main/assembly/dist.xml +++ b/extensions/guacamole-auth-jdbc/src/main/assembly/dist.xml @@ -27,6 +27,19 @@ + + + /postgresql/schema + modules/guacamole-auth-jdbc-postgresql/schema + + + modules/guacamole-auth-jdbc-postgresql/target/extension + /postgresql + + *.jar + + + From dbab6acd2cf303c0f00a7c2478bc36fd1c7710e7 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 2 Mar 2015 19:47:42 -0800 Subject: [PATCH 11/23] GUAC-1103: No INSERT IGNORE in postgres. --- .../auth/jdbc/permission/ConnectionGroupPermissionMapper.xml | 2 +- .../auth/jdbc/permission/ConnectionPermissionMapper.xml | 2 +- .../guacamole/auth/jdbc/permission/SystemPermissionMapper.xml | 2 +- .../guacamole/auth/jdbc/permission/UserPermissionMapper.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml index aad1dc09f..0d9f25bec 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml @@ -103,7 +103,7 @@ - INSERT IGNORE INTO guacamole_connection_group_permission ( + INSERT INTO guacamole_connection_group_permission ( user_id, permission, connection_group_id diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml index f45778516..79e99e18d 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml @@ -103,7 +103,7 @@ - INSERT IGNORE INTO guacamole_connection_permission ( + INSERT INTO guacamole_connection_permission ( user_id, permission, connection_id diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml index d472dc2ba..f1222012c 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionMapper.xml @@ -78,7 +78,7 @@ - INSERT IGNORE INTO guacamole_system_permission ( + INSERT INTO guacamole_system_permission ( user_id, permission ) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml index 14ac6d9cb..e16f02291 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/UserPermissionMapper.xml @@ -109,7 +109,7 @@ - INSERT IGNORE INTO guacamole_user_permission ( + INSERT INTO guacamole_user_permission ( user_id, permission, affected_user_id From 187f61b4837427f5391bb11d9d40b652d9c5070b Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Mon, 2 Mar 2015 20:03:44 -0800 Subject: [PATCH 12/23] GUAC-1103: Explicitly cast strings to integers. --- .../auth/jdbc/connection/ConnectionMapper.xml | 18 +++++++++--------- .../jdbc/connection/ConnectionRecordMapper.xml | 4 ++-- .../auth/jdbc/connection/ParameterMapper.xml | 6 +++--- .../connectiongroup/ConnectionGroupMapper.xml | 16 ++++++++-------- .../ConnectionGroupPermissionMapper.xml | 6 +++--- .../permission/ConnectionPermissionMapper.xml | 8 ++++---- 6 files changed, 29 insertions(+), 29 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionMapper.xml index 249ca6e78..11d18a9b4 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionMapper.xml @@ -54,7 +54,7 @@ SELECT connection_id FROM guacamole_connection WHERE - parent_id = #{parentIdentifier,jdbcType=INTEGER} + parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer parent_id IS NULL @@ -64,7 +64,7 @@ FROM guacamole_connection JOIN guacamole_connection_permission ON guacamole_connection_permission.connection_id = guacamole_connection.connection_id WHERE - parent_id = #{parentIdentifier,jdbcType=INTEGER} + parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer parent_id IS NULL AND user_id = #{user.objectID,jdbcType=INTEGER} AND permission = 'READ' @@ -82,7 +82,7 @@ WHERE connection_id IN - #{identifier,jdbcType=INTEGER} + #{identifier,jdbcType=INTEGER}::integer @@ -100,7 +100,7 @@ WHERE guacamole_connection.connection_id IN - #{identifier,jdbcType=INTEGER} + #{identifier,jdbcType=INTEGER}::integer AND user_id = #{user.objectID,jdbcType=INTEGER} AND permission = 'READ' @@ -117,7 +117,7 @@ protocol FROM guacamole_connection WHERE - parent_id = #{parentIdentifier,jdbcType=INTEGER} + parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer parent_id IS NULL AND connection_name = #{name,jdbcType=VARCHAR} @@ -126,7 +126,7 @@ DELETE FROM guacamole_connection - WHERE connection_id = #{identifier,jdbcType=INTEGER} + WHERE connection_id = #{identifier,jdbcType=INTEGER}::integer @@ -140,7 +140,7 @@ ) VALUES ( #{object.name,jdbcType=VARCHAR}, - #{object.parentIdentifier,jdbcType=INTEGER}, + #{object.parentIdentifier,jdbcType=INTEGER}::integer, #{object.protocol,jdbcType=VARCHAR} ) @@ -150,9 +150,9 @@ UPDATE guacamole_connection SET connection_name = #{object.name,jdbcType=VARCHAR}, - parent_id = #{object.parentIdentifier,jdbcType=INTEGER}, + parent_id = #{object.parentIdentifier,jdbcType=INTEGER}::integer, protocol = #{object.protocol,jdbcType=VARCHAR} - WHERE connection_id = #{object.objectID,jdbcType=INTEGER} + WHERE connection_id = #{object.objectID,jdbcType=INTEGER}::integer \ No newline at end of file diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml index 41601b731..de5f53076 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionRecordMapper.xml @@ -47,7 +47,7 @@ FROM guacamole_connection_history JOIN guacamole_user ON guacamole_connection_history.user_id = guacamole_user.user_id WHERE - connection_id = #{identifier,jdbcType=INTEGER} + connection_id = #{identifier,jdbcType=INTEGER}::integer ORDER BY start_date DESC, end_date DESC @@ -64,7 +64,7 @@ end_date ) VALUES ( - #{record.connectionIdentifier,jdbcType=INTEGER}, + #{record.connectionIdentifier,jdbcType=INTEGER}::integer, #{record.userID,jdbcType=INTEGER}, #{record.startDate,jdbcType=TIMESTAMP}, #{record.endDate,jdbcType=TIMESTAMP} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ParameterMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ParameterMapper.xml index 55212d026..e3fe5d8e9 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ParameterMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connection/ParameterMapper.xml @@ -41,13 +41,13 @@ parameter_value FROM guacamole_connection_parameter WHERE - connection_id = #{identifier,jdbcType=INTEGER} + connection_id = #{identifier,jdbcType=INTEGER}::integer DELETE FROM guacamole_connection_parameter - WHERE connection_id = #{identifier,jdbcType=INTEGER} + WHERE connection_id = #{identifier,jdbcType=INTEGER}::integer @@ -60,7 +60,7 @@ ) VALUES - (#{parameter.connectionIdentifier,jdbcType=INTEGER}, + (#{parameter.connectionIdentifier,jdbcType=INTEGER}::integer, #{parameter.name,jdbcType=VARCHAR}, #{parameter.value,jdbcType=VARCHAR}) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml index 63bd1abae..0c5195990 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml @@ -55,7 +55,7 @@ SELECT connection_group_id FROM guacamole_connection_group WHERE - parent_id = #{parentIdentifier,jdbcType=INTEGER} + parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer parent_id IS NULL @@ -65,7 +65,7 @@ FROM guacamole_connection_group JOIN guacamole_connection_group_permission ON guacamole_connection_group_permission.connection_group_id = guacamole_connection_group.connection_group_id WHERE - parent_id = #{parentIdentifier,jdbcType=INTEGER} + parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer parent_id IS NULL AND user_id = #{user.objectID,jdbcType=INTEGER} AND permission = 'READ' @@ -101,7 +101,7 @@ WHERE guacamole_connection_group.connection_group_id IN - #{identifier,jdbcType=INTEGER} + #{identifier,jdbcType=INTEGER}::integer AND user_id = #{user.objectID,jdbcType=INTEGER} AND permission = 'READ' @@ -118,7 +118,7 @@ type FROM guacamole_connection_group WHERE - parent_id = #{parentIdentifier,jdbcType=INTEGER} + parent_id = #{parentIdentifier,jdbcType=INTEGER}::integer parent_id IS NULL AND connection_group_name = #{name,jdbcType=VARCHAR} @@ -127,7 +127,7 @@ DELETE FROM guacamole_connection_group - WHERE connection_group_id = #{identifier,jdbcType=INTEGER} + WHERE connection_group_id = #{identifier,jdbcType=INTEGER}::integer @@ -141,7 +141,7 @@ ) VALUES ( #{object.name,jdbcType=VARCHAR}, - #{object.parentIdentifier,jdbcType=INTEGER}, + #{object.parentIdentifier,jdbcType=INTEGER}::integer, #{object.type,jdbcType=VARCHAR} ) @@ -151,9 +151,9 @@ UPDATE guacamole_connection_group SET connection_group_name = #{object.name,jdbcType=VARCHAR}, - parent_id = #{object.parentIdentifier,jdbcType=INTEGER}, + parent_id = #{object.parentIdentifier,jdbcType=INTEGER}::integer, type = #{object.type,jdbcType=VARCHAR} - WHERE connection_group_id = #{object.objectID,jdbcType=INTEGER} + WHERE connection_group_id = #{object.objectID,jdbcType=INTEGER}::integer \ No newline at end of file diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml index 0d9f25bec..33b3562ed 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionGroupPermissionMapper.xml @@ -62,7 +62,7 @@ WHERE guacamole_connection_group_permission.user_id = #{user.objectID,jdbcType=INTEGER} AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type - AND connection_group_id = #{identifier,jdbcType=INTEGER} + AND connection_group_id = #{identifier,jdbcType=INTEGER}::integer @@ -76,7 +76,7 @@ AND connection_group_id IN - #{identifier,jdbcType=INTEGER} + #{identifier,jdbcType=INTEGER}::integer AND permission IN (#{permission.userID,jdbcType=INTEGER}, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, - #{permission.objectIdentifier,jdbcType=INTEGER}) + #{permission.objectIdentifier,jdbcType=INTEGER}::integer) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml index 79e99e18d..4ed1ad7e9 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/permission/ConnectionPermissionMapper.xml @@ -62,7 +62,7 @@ WHERE guacamole_connection_permission.user_id = #{user.objectID,jdbcType=INTEGER} AND permission = #{type,jdbcType=VARCHAR}::guacamole_object_permission_type - AND connection_id = #{identifier,jdbcType=INTEGER} + AND connection_id = #{identifier,jdbcType=INTEGER}::integer @@ -76,7 +76,7 @@ AND connection_id IN - #{identifier,jdbcType=INTEGER} + #{identifier,jdbcType=INTEGER}::integer AND permission IN (#{permission.userID,jdbcType=INTEGER}, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, - #{permission.objectIdentifier,jdbcType=INTEGER}) + #{permission.objectIdentifier,jdbcType=INTEGER}::integer) @@ -112,7 +112,7 @@ (#{permission.userID,jdbcType=INTEGER}, #{permission.type,jdbcType=VARCHAR}::guacamole_object_permission_type, - #{permission.objectIdentifier,jdbcType=INTEGER}) + #{permission.objectIdentifier,jdbcType=INTEGER}::integer) From 4fb2f4e04773bfd10685890846eae34099891507 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Thu, 5 Mar 2015 11:45:03 -0800 Subject: [PATCH 13/23] GUAC-1103: Allow unsalted passwords from external systems. --- .../security/PasswordEncryptionService.java | 13 ++++++++---- .../SHA256PasswordEncryptionService.java | 20 +++++++++---------- .../schema/001-create-schema.sql | 6 ++++-- .../schema/001-create-schema.sql | 6 ++++-- 4 files changed, 27 insertions(+), 18 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/PasswordEncryptionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/PasswordEncryptionService.java index ef3099468..2e78725ef 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/PasswordEncryptionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/PasswordEncryptionService.java @@ -30,11 +30,16 @@ public interface PasswordEncryptionService { /** * Creates a password hash based on the provided username, password, and - * salt. + * salt. If the provided salt is null, only the password itself is hashed. * - * @param password The password to hash. - * @param salt The salt to use when hashing the password. - * @return The generated password hash. + * @param password + * The password to hash. + * + * @param salt + * The salt to use when hashing the password, if any. + * + * @return + * The generated password hash. */ public byte[] createPasswordHash(String password, byte[] salt); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/SHA256PasswordEncryptionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/SHA256PasswordEncryptionService.java index cfe5bc45f..577bdb0ef 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/SHA256PasswordEncryptionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/security/SHA256PasswordEncryptionService.java @@ -38,26 +38,26 @@ public class SHA256PasswordEncryptionService implements PasswordEncryptionServic try { - // Build salted password + // Build salted password, if a salt was provided StringBuilder builder = new StringBuilder(); builder.append(password); - builder.append(DatatypeConverter.printHexBinary(salt)); - // Hash UTF-8 bytes of salted password + if (salt != null) + builder.append(DatatypeConverter.printHexBinary(salt)); + + // Hash UTF-8 bytes of possibly-salted password MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(builder.toString().getBytes("UTF-8")); return md.digest(); } - // Should not happen - catch (UnsupportedEncodingException ex) { - throw new RuntimeException(ex); + // Throw hard errors if standard pieces of Java are missing + catch (UnsupportedEncodingException e) { + throw new UnsupportedOperationException("Unexpected lack of UTF-8 support.", e); } - - // Should not happen - catch (NoSuchAlgorithmException ex) { - throw new RuntimeException(ex); + catch (NoSuchAlgorithmException e) { + throw new UnsupportedOperationException("Unexpected lack of SHA-256 support.", e); } } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql index 5c23bfc90..0a50bb379 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/schema/001-create-schema.sql @@ -65,7 +65,9 @@ CREATE TABLE `guacamole_connection` ( -- -- Table of users. Each user has a unique username and a hashed password --- with corresponding salt. +-- with corresponding salt. Although the authentication system will always set +-- salted passwords, other systems may set unsalted passwords by simply not +-- providing the salt. -- CREATE TABLE `guacamole_user` ( @@ -73,7 +75,7 @@ CREATE TABLE `guacamole_user` ( `user_id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(128) NOT NULL, `password_hash` binary(32) NOT NULL, - `password_salt` binary(32) NOT NULL, + `password_salt` binary(32), PRIMARY KEY (`user_id`), UNIQUE KEY `username` (`username`) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql index a52fefecc..4e4297693 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/001-create-schema.sql @@ -106,7 +106,9 @@ CREATE INDEX ON guacamole_connection(parent_id); -- -- Table of users. Each user has a unique username and a hashed password --- with corresponding salt. +-- with corresponding salt. Although the authentication system will always set +-- salted passwords, other systems may set unsalted passwords by simply not +-- providing the salt. -- CREATE TABLE guacamole_user ( @@ -114,7 +116,7 @@ CREATE TABLE guacamole_user ( user_id serial NOT NULL, username varchar(128) NOT NULL, password_hash bytea NOT NULL, - password_salt bytea NOT NULL, + password_salt bytea, PRIMARY KEY (user_id), From 8f557ed338c10a64aea678543af1bcf91eb80847 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Fri, 6 Mar 2015 12:48:06 -0800 Subject: [PATCH 14/23] GUAC-1103: Fix guacadmin user creation script. Must not insert IDs directly into serial columns - doing so clashes with the sequence resulting in PK failures upon insert. --- .../schema/002-create-admin-user.sql | 33 ++++++++++++++----- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql index 9b912548d..16eafbe73 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/schema/002-create-admin-user.sql @@ -20,19 +20,34 @@ -- THE SOFTWARE. -- + -- Create default user "guacadmin" with password "guacadmin" -insert into guacamole_user values(1, 'guacadmin', +INSERT INTO guacamole_user (username, password_hash, password_salt) +VALUES ('guacadmin', E'\\xCA458A7D494E3BE824F5E1E175A1556C0F8EEF2C2D7DF3633BEC4A29C4411960', -- 'guacadmin' E'\\xFE24ADC5E11E2B25288D1704ABE67A79E342ECC26064CE69C5B3177795A82264'); --- Grant this user create permissions -insert into guacamole_system_permission values(1, 'CREATE_CONNECTION'); -insert into guacamole_system_permission values(1, 'CREATE_CONNECTION_GROUP'); -insert into guacamole_system_permission values(1, 'CREATE_USER'); -insert into guacamole_system_permission values(1, 'ADMINISTER'); +-- Grant this user all system permissions +INSERT INTO guacamole_system_permission +SELECT user_id, permission::guacamole_system_permission_type +FROM ( + VALUES + ('guacadmin', 'CREATE_CONNECTION'), + ('guacadmin', 'CREATE_CONNECTION_GROUP'), + ('guacadmin', 'CREATE_USER'), + ('guacadmin', 'ADMINISTER') +) permissions (username, permission) +JOIN guacamole_user ON permissions.username = guacamole_user.username; -- Grant admin permission to read/update/administer self -insert into guacamole_user_permission values(1, 1, 'READ'); -insert into guacamole_user_permission values(1, 1, 'UPDATE'); -insert into guacamole_user_permission values(1, 1, 'ADMINISTER'); +INSERT INTO guacamole_user_permission +SELECT guacamole_user.user_id, affected.user_id, permission::guacamole_object_permission_type +FROM ( + VALUES + ('guacadmin', 'guacadmin', 'READ'), + ('guacadmin', 'guacadmin', 'UPDATE'), + ('guacadmin', 'guacadmin', 'ADMINISTER') +) permissions (username, affected_username, permission) +JOIN guacamole_user ON permissions.username = guacamole_user.username +JOIN guacamole_user affected ON permissions.affected_username = affected.username; From db6a9f07a3083b36f94bbbe8ea457d5b8546a1da Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Fri, 6 Mar 2015 12:50:33 -0800 Subject: [PATCH 15/23] GUAC-1103: Fix case of user READ permission. --- .../org/glyptodon/guacamole/auth/jdbc/user/UserMapper.xml | 4 ++-- .../org/glyptodon/guacamole/auth/jdbc/user/UserMapper.xml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/user/UserMapper.xml index 69c49d060..7c5b7357f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/user/UserMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-mysql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/user/UserMapper.xml @@ -47,7 +47,7 @@ JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id WHERE guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} - AND permission = 'read' + AND permission = 'READ' @@ -83,7 +83,7 @@ #{identifier,jdbcType=VARCHAR} AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} - AND permission = 'read' + AND permission = 'READ' diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/user/UserMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/user/UserMapper.xml index 5170d43ee..41416f7db 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/user/UserMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/user/UserMapper.xml @@ -47,7 +47,7 @@ JOIN guacamole_user_permission ON affected_user_id = guacamole_user.user_id WHERE guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} - AND permission = 'read' + AND permission = 'READ' @@ -83,7 +83,7 @@ #{identifier,jdbcType=VARCHAR} AND guacamole_user_permission.user_id = #{user.objectID,jdbcType=INTEGER} - AND permission = 'read' + AND permission = 'READ' From ee3d8f77c23698c37435c3faf0fc57a3d3344226 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Fri, 6 Mar 2015 13:03:41 -0800 Subject: [PATCH 16/23] GUAC-1103: Add missing typecase for connection group type. --- .../auth/jdbc/connectiongroup/ConnectionGroupMapper.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml index 0c5195990..f437e51a0 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml @@ -142,7 +142,7 @@ VALUES ( #{object.name,jdbcType=VARCHAR}, #{object.parentIdentifier,jdbcType=INTEGER}::integer, - #{object.type,jdbcType=VARCHAR} + #{object.type,jdbcType=VARCHAR}::guacamole_connection_group_type ) @@ -152,7 +152,7 @@ UPDATE guacamole_connection_group SET connection_group_name = #{object.name,jdbcType=VARCHAR}, parent_id = #{object.parentIdentifier,jdbcType=INTEGER}::integer, - type = #{object.type,jdbcType=VARCHAR} + type = #{object.type,jdbcType=VARCHAR}::guacamole_connection_group_type WHERE connection_group_id = #{object.objectID,jdbcType=INTEGER}::integer From 40bdfb57b3928295263bdd7d19e30c4c63487208 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Fri, 6 Mar 2015 13:14:33 -0800 Subject: [PATCH 17/23] GUAC-1103: Update README to include PostgresQL. --- extensions/guacamole-auth-jdbc/README | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/extensions/guacamole-auth-jdbc/README b/extensions/guacamole-auth-jdbc/README index d4fa250aa..0fee7bc93 100644 --- a/extensions/guacamole-auth-jdbc/README +++ b/extensions/guacamole-auth-jdbc/README @@ -51,8 +51,8 @@ in the library directory configured in guacamole.properties. created in the target/ subdirectory of the current directory. 4) Extract the .tar.gz file now present in the target/ directory, and - place the .jar files in the extracted lib/ subdirectory in the library - directory specified in guacamole.properties. + place the .jar files from the extracted database-specific subdirectory in + the library directory specified in guacamole.properties. You will likely need to do this as root. @@ -60,10 +60,10 @@ in the library directory configured in guacamole.properties. guacamole.properties, you will need to specify one. The directory is specified using the "lib-directory" property. -5) Set up your MySQL database to authenticate Guacamole users +5) Set up your database to authenticate Guacamole users A schema file is provided in the schema directory for creating - the guacamole authentication tables in your MySQL database. + the guacamole authentication tables in your database of choice. Additionally, a script is provided to create a default admin user with username 'guacadmin' and password 'guacadmin'. This user can @@ -90,6 +90,17 @@ in the library directory configured in guacamole.properties. mysql-disallow-simultaneous-connections: true + For PostgreSQL, the properties are the same, but have different prefixes: + + # Database connection configuration + postgresql-hostname: database.host.name + postgresql-port: 5432 + postgresql-database: guacamole.database.name + postgresql-username: user + postgresql-password: pass + + postgresql-disallow-simultaneous-connections: true + ------------------------------------------------------------ Reporting problems From eb676c8b3f820549491054d91003f24e97601170 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 7 Mar 2015 14:06:27 -0800 Subject: [PATCH 18/23] GUAC-1104: Move parent identifier functions to common base objects. --- .../jdbc/base/GroupedDirectoryObject.java | 78 +++++++++++++++++++ .../auth/jdbc/base/GroupedObjectModel.java | 67 ++++++++++++++++ .../auth/jdbc/connection/ConnectionModel.java | 33 +------- .../jdbc/connection/ModeledConnection.java | 31 +------- .../connectiongroup/ConnectionGroupModel.java | 33 +------- .../ModeledConnectionGroup.java | 28 +------ 6 files changed, 154 insertions(+), 116 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/GroupedDirectoryObject.java create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/GroupedObjectModel.java diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/GroupedDirectoryObject.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/GroupedDirectoryObject.java new file mode 100644 index 000000000..2b804be85 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/GroupedDirectoryObject.java @@ -0,0 +1,78 @@ +/* + * 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.auth.jdbc.base; + +import org.glyptodon.guacamole.auth.jdbc.connectiongroup.RootConnectionGroup; + +/** + * Common base class for objects that will ultimately be made available through + * the Directory class. All such objects will need the same base set of queries + * to fulfill the needs of the Directory class. + * + * @author Michael Jumper + * @param + * The type of model object that corresponds to this object. + */ +public abstract class GroupedDirectoryObject + extends DirectoryObject { + + /** + * Returns the identifier of the parent connection group, which cannot be + * null. If the parent is the root connection group, this will be + * RootConnectionGroup.IDENTIFIER. + * + * @return + * The identifier of the parent connection group. + */ + public String getParentIdentifier() { + + // Translate null parent to proper identifier + String parentIdentifier = getModel().getParentIdentifier(); + if (parentIdentifier == null) + return RootConnectionGroup.IDENTIFIER; + + return parentIdentifier; + + } + + /** + * Sets the identifier of the associated parent connection group. If the + * parent is the root connection group, this should be + * RootConnectionGroup.IDENTIFIER. + * + * @param parentIdentifier + * The identifier of the connection group to associate as this object's + * parent. + */ + public void setParentIdentifier(String parentIdentifier) { + + // Translate root identifier back into null + if (parentIdentifier != null + && parentIdentifier.equals(RootConnectionGroup.IDENTIFIER)) + parentIdentifier = null; + + getModel().setParentIdentifier(parentIdentifier); + + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/GroupedObjectModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/GroupedObjectModel.java new file mode 100644 index 000000000..45b25598a --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/GroupedObjectModel.java @@ -0,0 +1,67 @@ +/* + * 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.auth.jdbc.base; + +/** + * Object representation of a Guacamole object, such as a user or connection, + * as represented in the database. + * + * @author Michael Jumper + */ +public abstract class GroupedObjectModel extends ObjectModel { + + /** + * The unique identifier which identifies the parent of this object. + */ + private String parentIdentifier; + + /** + * Creates a new, empty object. + */ + public GroupedObjectModel() { + } + + /** + * Returns the identifier of the parent connection group, or null if the + * parent connection group is the root connection group. + * + * @return + * The identifier of the parent connection group, or null if the parent + * connection group is the root connection group. + */ + public String getParentIdentifier() { + return parentIdentifier; + } + + /** + * Sets the identifier of the parent connection group. + * + * @param parentIdentifier + * The identifier of the parent connection group, or null if the parent + * connection group is the root connection group. + */ + public void setParentIdentifier(String parentIdentifier) { + this.parentIdentifier = parentIdentifier; + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionModel.java index b4ef2e907..5b3552fe9 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionModel.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionModel.java @@ -22,7 +22,7 @@ package org.glyptodon.guacamole.auth.jdbc.connection; -import org.glyptodon.guacamole.auth.jdbc.base.ObjectModel; +import org.glyptodon.guacamole.auth.jdbc.base.GroupedObjectModel; /** * Object representation of a Guacamole connection, as represented in the @@ -30,14 +30,8 @@ import org.glyptodon.guacamole.auth.jdbc.base.ObjectModel; * * @author Michael Jumper */ -public class ConnectionModel extends ObjectModel { +public class ConnectionModel extends GroupedObjectModel { - /** - * The identifier of the parent connection group in the database, or null - * if the parent connection group is the root group. - */ - private String parentIdentifier; - /** * The human-readable name associated with this connection. */ @@ -95,29 +89,6 @@ public class ConnectionModel extends ObjectModel { this.protocol = protocol; } - /** - * Returns the identifier of the parent connection group, or null if the - * parent connection group is the root connection group. - * - * @return - * The identifier of the parent connection group, or null if the parent - * connection group is the root connection group. - */ - public String getParentIdentifier() { - return parentIdentifier; - } - - /** - * Sets the identifier of the parent connection group. - * - * @param parentIdentifier - * The identifier of the parent connection group, or null if the parent - * connection group is the root connection group. - */ - public void setParentIdentifier(String parentIdentifier) { - this.parentIdentifier = parentIdentifier; - } - @Override public String getIdentifier() { diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnection.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnection.java index 64cb1232c..b1f532e80 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnection.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnection.java @@ -25,10 +25,9 @@ package org.glyptodon.guacamole.auth.jdbc.connection; import com.google.inject.Inject; import com.google.inject.Provider; import java.util.List; -import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObject; -import org.glyptodon.guacamole.auth.jdbc.connectiongroup.RootConnectionGroup; import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService; import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.auth.jdbc.base.GroupedDirectoryObject; import org.glyptodon.guacamole.net.GuacamoleSocket; import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionRecord; @@ -42,7 +41,7 @@ import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; * @author James Muehlner * @author Michael Jumper */ -public class ModeledConnection extends DirectoryObject +public class ModeledConnection extends GroupedDirectoryObject implements Connection { /** @@ -67,7 +66,7 @@ public class ModeledConnection extends DirectoryObject * The manually-set GuacamoleConfiguration, if any. */ private GuacamoleConfiguration config = null; - + /** * Creates a new, empty ModeledConnection. */ @@ -84,30 +83,6 @@ public class ModeledConnection extends DirectoryObject getModel().setName(name); } - @Override - public String getParentIdentifier() { - - // Translate null parent to proper identifier - String parentIdentifier = getModel().getParentIdentifier(); - if (parentIdentifier == null) - return RootConnectionGroup.IDENTIFIER; - - return parentIdentifier; - - } - - @Override - public void setParentIdentifier(String parentIdentifier) { - - // Translate root identifier back into null - if (parentIdentifier != null - && parentIdentifier.equals(RootConnectionGroup.IDENTIFIER)) - parentIdentifier = null; - - getModel().setParentIdentifier(parentIdentifier); - - } - @Override public GuacamoleConfiguration getConfiguration() { diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupModel.java index 68845df9c..def543ffc 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupModel.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupModel.java @@ -22,7 +22,7 @@ package org.glyptodon.guacamole.auth.jdbc.connectiongroup; -import org.glyptodon.guacamole.auth.jdbc.base.ObjectModel; +import org.glyptodon.guacamole.auth.jdbc.base.GroupedObjectModel; import org.glyptodon.guacamole.net.auth.ConnectionGroup; /** @@ -31,14 +31,8 @@ import org.glyptodon.guacamole.net.auth.ConnectionGroup; * * @author Michael Jumper */ -public class ConnectionGroupModel extends ObjectModel { +public class ConnectionGroupModel extends GroupedObjectModel { - /** - * The identifier of the parent connection group in the database, or null - * if the parent connection group is the root group. - */ - private String parentIdentifier; - /** * The human-readable name associated with this connection group. */ @@ -75,29 +69,6 @@ public class ConnectionGroupModel extends ObjectModel { this.name = name; } - /** - * Returns the identifier of the parent connection group, or null if the - * parent connection group is the root connection group. - * - * @return - * The identifier of the parent connection group, or null if the parent - * connection group is the root connection group. - */ - public String getParentIdentifier() { - return parentIdentifier; - } - - /** - * Sets the identifier of the parent connection group. - * - * @param parentIdentifier - * The identifier of the parent connection group, or null if the parent - * connection group is the root connection group. - */ - public void setParentIdentifier(String parentIdentifier) { - this.parentIdentifier = parentIdentifier; - } - /** * Returns the type of this connection group, such as organizational or * balancing. diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ModeledConnectionGroup.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ModeledConnectionGroup.java index cad15286c..52b71e0e2 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ModeledConnectionGroup.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ModeledConnectionGroup.java @@ -24,10 +24,10 @@ package org.glyptodon.guacamole.auth.jdbc.connectiongroup; import com.google.inject.Inject; import java.util.Set; -import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObject; import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionService; import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService; import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.auth.jdbc.base.GroupedDirectoryObject; import org.glyptodon.guacamole.net.GuacamoleSocket; import org.glyptodon.guacamole.net.auth.ConnectionGroup; import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; @@ -38,7 +38,7 @@ import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; * * @author James Muehlner */ -public class ModeledConnectionGroup extends DirectoryObject +public class ModeledConnectionGroup extends GroupedDirectoryObject implements ConnectionGroup { /** @@ -75,30 +75,6 @@ public class ModeledConnectionGroup extends DirectoryObject Date: Sat, 7 Mar 2015 15:13:51 -0800 Subject: [PATCH 19/23] GUAC-1104: Add parent group validation. Switch to beforeCreate/beforeUpdate/beforeDelete validation functions. --- .../jdbc/base/DirectoryObjectService.java | 150 +++++++------- .../base/GroupedDirectoryObjectService.java | 196 ++++++++++++++++++ .../jdbc/connection/ConnectionService.java | 14 +- .../ConnectionGroupService.java | 12 +- .../guacamole/auth/jdbc/user/UserService.java | 8 +- 5 files changed, 296 insertions(+), 84 deletions(-) create mode 100644 extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/GroupedDirectoryObjectService.java diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/DirectoryObjectService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/DirectoryObjectService.java index fc2bdb331..5a67b24b6 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/DirectoryObjectService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/base/DirectoryObjectService.java @@ -37,8 +37,8 @@ import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet; /** * Service which provides convenience methods for creating, retrieving, and - * manipulating users. This service will automatically enforce the - * permissions of the current user. + * manipulating objects within directories. This service will automatically + * enforce the permissions of the current user. * * @author Michael Jumper * @param @@ -215,52 +215,77 @@ public abstract class DirectoryObjectService implicitPermissions = + new ArrayList(IMPLICIT_OBJECT_PERMISSIONS.length); - // Create object - getObjectMapper().insert(model); + UserModel userModel = user.getUser().getModel(); + for (ObjectPermission.Type permission : IMPLICIT_OBJECT_PERMISSIONS) { - // Build list of implicit permissions - Collection implicitPermissions = - new ArrayList(IMPLICIT_OBJECT_PERMISSIONS.length); + // Create model which grants this permission to the current user + ObjectPermissionModel permissionModel = new ObjectPermissionModel(); + permissionModel.setUserID(userModel.getObjectID()); + permissionModel.setUsername(userModel.getIdentifier()); + permissionModel.setType(permission); + permissionModel.setObjectIdentifier(model.getIdentifier()); - UserModel userModel = user.getUser().getModel(); - for (ObjectPermission.Type permission : IMPLICIT_OBJECT_PERMISSIONS) { - - // Create model which grants this permission to the current user - ObjectPermissionModel permissionModel = new ObjectPermissionModel(); - permissionModel.setUserID(userModel.getObjectID()); - permissionModel.setUsername(userModel.getIdentifier()); - permissionModel.setType(permission); - permissionModel.setObjectIdentifier(model.getIdentifier()); - - // Add permission - implicitPermissions.add(permissionModel); - - } - - // Add implicit permissions - getPermissionMapper().insert(implicitPermissions); - - return getObjectInstance(user, model); + // Add permission + implicitPermissions.add(permissionModel); + } - // User lacks permission to create - throw new GuacamoleSecurityException("Permission denied."); + // Add implicit permissions + getPermissionMapper().insert(implicitPermissions); + + return getObjectInstance(user, model); } @@ -416,14 +433,10 @@ public abstract class DirectoryObjectService + * The specific internal implementation of the type of object this service + * provides access to. + * + * @param + * The external interface or implementation of the type of object this + * service provides access to, as defined by the guacamole-ext API. + * + * @param + * The underlying model object used to represent InternalType in the + * database. + */ +public abstract class GroupedDirectoryObjectService, + ExternalType, ModelType extends GroupedObjectModel> + extends DirectoryObjectService { + + /** + * Returns the set of parent connection groups that are modified by the + * given model object (by virtue of the object changing parent groups). If + * the model is not changing parents, the resulting collection will be + * empty. + * + * @param user + * The user making the given changes to the model. + * + * @param identifier + * The identifier of the object that has been modified, if it exists. + * If the object is being created, this will be null. + * + * @param model + * The model that has been modified, if any. If the object is being + * deleted, this will be null. + * + * @return + * A collection of the identifiers of all parent connection groups + * that will be affected (updated) by the change. + * + * @throws GuacamoleException + * If an error occurs while determining which parent connection groups + * are affected. + */ + protected Collection getModifiedGroups(AuthenticatedUser user, + String identifier, ModelType model) throws GuacamoleException { + + // Get old parent identifier + String oldParentIdentifier = null; + if (identifier != null) { + ModelType current = retrieveObject(user, identifier).getModel(); + oldParentIdentifier = current.getParentIdentifier(); + } + + // Get new parent identifier + String parentIdentifier = null; + if (model != null) { + + parentIdentifier = model.getParentIdentifier(); + + // If both parents have the same identifier, nothing has changed + if (parentIdentifier != null && parentIdentifier.equals(oldParentIdentifier)) + return Collections.EMPTY_LIST; + + } + + // Return collection of all non-root groups involved + Collection groups = new ArrayList(2); + if (oldParentIdentifier != null) groups.add(oldParentIdentifier); + if (parentIdentifier != null) groups.add(parentIdentifier); + return groups; + + } + + /** + * Returns whether the given user has permission to modify the parent + * connection groups affected by the modifications made to the given model + * object. + * + * @param user + * The user who changed the model object. + * + * @param identifier + * The identifier of the object that has been modified, if it exists. + * If the object is being created, this will be null. + * + * @param model + * The model that has been modified, if any. If the object is being + * deleted, this will be null. + * + * @return + * true if the user has update permission for all modified groups, + * false otherwise. + * + * @throws GuacamoleException + * If an error occurs while determining which parent connection groups + * are affected. + */ + protected boolean canUpdateModifiedGroups(AuthenticatedUser user, + String identifier, ModelType model) throws GuacamoleException { + + // If user is an administrator, no need to check + if (user.getUser().isAdministrator()) + return true; + + // Verify that we have permission to modify any modified groups + Collection modifiedGroups = getModifiedGroups(user, identifier, model); + if (!modifiedGroups.isEmpty()) { + + ObjectPermissionSet permissionSet = user.getUser().getConnectionGroupPermissions(); + Collection updateableGroups = permissionSet.getAccessibleObjects( + Collections.singleton(ObjectPermission.Type.UPDATE), + modifiedGroups + ); + + return updateableGroups.size() == modifiedGroups.size(); + + } + + return true; + + } + + @Override + protected void beforeCreate(AuthenticatedUser user, + ModelType model) throws GuacamoleException { + + super.beforeCreate(user, model); + + // Validate that we can update all applicable parent groups + if (!canUpdateModifiedGroups(user, null, model)) + throw new GuacamoleSecurityException("Permission denied."); + + } + + @Override + protected void beforeUpdate(AuthenticatedUser user, + ModelType model) throws GuacamoleException { + + super.beforeUpdate(user, model); + + // Validate that we can update all applicable parent groups + if (!canUpdateModifiedGroups(user, model.getIdentifier(), model)) + throw new GuacamoleSecurityException("Permission denied."); + + } + + @Override + protected void beforeDelete(AuthenticatedUser user, + String identifier) throws GuacamoleException { + + super.beforeDelete(user, identifier); + + // Validate that we can update all applicable parent groups + if (!canUpdateModifiedGroups(user, identifier, null)) + throw new GuacamoleSecurityException("Permission denied."); + + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionService.java index 9bf566770..8ac5d5da7 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ConnectionService.java @@ -33,11 +33,11 @@ import java.util.Map; import java.util.Set; import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectMapper; -import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectService; import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService; import org.glyptodon.guacamole.GuacamoleClientException; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleSecurityException; +import org.glyptodon.guacamole.auth.jdbc.base.GroupedDirectoryObjectService; import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionPermissionMapper; import org.glyptodon.guacamole.auth.jdbc.permission.ObjectPermissionMapper; import org.glyptodon.guacamole.net.GuacamoleSocket; @@ -55,7 +55,7 @@ import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; * * @author Michael Jumper, James Muehlner */ -public class ConnectionService extends DirectoryObjectService { +public class ConnectionService extends GroupedDirectoryObjectService { /** * Mapper for accessing connections. @@ -148,9 +148,11 @@ public class ConnectionService extends DirectoryObjectService { /** @@ -130,9 +130,11 @@ public class ConnectionGroupService extends DirectoryObjectService Date: Sat, 7 Mar 2015 19:01:16 -0800 Subject: [PATCH 20/23] GUAC-1103: Add missing explicit typecast. --- .../auth/jdbc/connectiongroup/ConnectionGroupMapper.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml index f437e51a0..3acf3731f 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-postgresql/src/main/resources/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupMapper.xml @@ -83,7 +83,7 @@ WHERE connection_group_id IN - #{identifier,jdbcType=INTEGER} + #{identifier,jdbcType=INTEGER}::integer From 0ed12dc0eb7486b6dd598d10487a7fa43854629b Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 7 Mar 2015 19:15:45 -0800 Subject: [PATCH 21/23] GUAC-1114: Do not allow users to delete themselves. --- .../guacamole/auth/jdbc/user/UserService.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserService.java index 68458b78b..2db7f3d96 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserService.java @@ -32,6 +32,7 @@ import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectMapper; import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectService; import org.glyptodon.guacamole.GuacamoleClientException; import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.GuacamoleUnsupportedException; import org.glyptodon.guacamole.auth.jdbc.permission.ObjectPermissionMapper; import org.glyptodon.guacamole.auth.jdbc.permission.UserPermissionMapper; import org.glyptodon.guacamole.auth.jdbc.security.PasswordEncryptionService; @@ -164,6 +165,17 @@ public class UserService extends DirectoryObjectService Date: Sat, 7 Mar 2015 19:24:36 -0800 Subject: [PATCH 22/23] GUAC-1114: Do not allow users to remove their own system permissions. --- .../auth/jdbc/permission/SystemPermissionService.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionService.java index 52edda6d0..2a7837e58 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/permission/SystemPermissionService.java @@ -29,6 +29,7 @@ import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; import org.glyptodon.guacamole.auth.jdbc.user.ModeledUser; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleSecurityException; +import org.glyptodon.guacamole.GuacamoleUnsupportedException; import org.glyptodon.guacamole.net.auth.permission.SystemPermission; /** @@ -112,6 +113,11 @@ public class SystemPermissionService // Only an admin can delete system permissions if (user.getUser().isAdministrator()) { + + // Do not allow users to remove their own admin powers + if (user.getUser().getIdentifier().equals(targetUser.getIdentifier())) + throw new GuacamoleUnsupportedException("Removing your own administrative permissions is not allowed."); + Collection models = getModelInstances(targetUser, permissions); systemPermissionMapper.delete(models); return; From f38c246ad020d93ee31bc589410d47a02232c8b6 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 7 Mar 2015 22:06:54 -0800 Subject: [PATCH 23/23] GUAC-1110: Do not allow connection groups to be updated if doing so would create a cycle. --- .../connectiongroup/ConnectionGroupService.java | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java index aea294221..bca97adb6 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connectiongroup/ConnectionGroupService.java @@ -31,6 +31,7 @@ import org.glyptodon.guacamole.auth.jdbc.socket.GuacamoleSocketService; import org.glyptodon.guacamole.GuacamoleClientException; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleSecurityException; +import org.glyptodon.guacamole.GuacamoleUnsupportedException; import org.glyptodon.guacamole.auth.jdbc.base.GroupedDirectoryObjectService; import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionGroupPermissionMapper; import org.glyptodon.guacamole.auth.jdbc.permission.ObjectPermissionMapper; @@ -165,7 +166,21 @@ public class ConnectionGroupService extends GroupedDirectoryObjectService