diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java index a02012a90..d63161a82 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/JDBCAuthenticationProviderModule.java @@ -57,6 +57,9 @@ import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionPermissionSet; import org.glyptodon.guacamole.auth.jdbc.permission.UserPermissionMapper; import org.glyptodon.guacamole.auth.jdbc.permission.UserPermissionService; import org.glyptodon.guacamole.auth.jdbc.permission.UserPermissionSet; +import org.glyptodon.guacamole.auth.jdbc.activeconnection.ActiveConnectionDirectory; +import org.glyptodon.guacamole.auth.jdbc.activeconnection.ActiveConnectionService; +import org.glyptodon.guacamole.auth.jdbc.activeconnection.TrackedActiveConnection; import org.glyptodon.guacamole.environment.Environment; import org.mybatis.guice.MyBatisModule; import org.mybatis.guice.datasource.builtin.PooledDataSourceProvider; @@ -120,6 +123,7 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule { addMapperClass(UserPermissionMapper.class); // Bind core implementations of guacamole-ext classes + bind(ActiveConnectionDirectory.class); bind(Environment.class).toInstance(environment); bind(ConnectionDirectory.class); bind(ConnectionGroupDirectory.class); @@ -131,11 +135,13 @@ public class JDBCAuthenticationProviderModule extends MyBatisModule { bind(ModeledUser.class); bind(RootConnectionGroup.class); bind(SystemPermissionSet.class); + bind(TrackedActiveConnection.class); bind(UserContext.class); bind(UserDirectory.class); bind(UserPermissionSet.class); // Bind services + bind(ActiveConnectionService.class); bind(ConnectionGroupPermissionService.class); bind(ConnectionGroupService.class); bind(ConnectionPermissionService.class); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/ActiveConnectionDirectory.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/ActiveConnectionDirectory.java new file mode 100644 index 000000000..72d036813 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/ActiveConnectionDirectory.java @@ -0,0 +1,83 @@ +/* + * 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.jdbc.activeconnection; + + +import com.google.inject.Inject; +import java.util.Collection; +import java.util.Collections; +import java.util.Set; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.auth.jdbc.base.RestrictedObject; +import org.glyptodon.guacamole.net.auth.ActiveConnection; +import org.glyptodon.guacamole.net.auth.Directory; + +/** + * Implementation of a Directory which contains all currently-active + * connections. + * + * @author Michael Jumper + */ +public class ActiveConnectionDirectory extends RestrictedObject + implements Directory { + + /** + * Service for retrieving and manipulating active connections. + */ + @Inject + private ActiveConnectionService activeConnectionService; + + @Override + public ActiveConnection get(String identifier) throws GuacamoleException { + return activeConnectionService.retrieveObject(getCurrentUser(), identifier); + } + + @Override + public Collection getAll(Collection identifiers) + throws GuacamoleException { + Collection objects = activeConnectionService.retrieveObjects(getCurrentUser(), identifiers); + return Collections.unmodifiableCollection(objects); + } + + @Override + public Set getIdentifiers() throws GuacamoleException { + return activeConnectionService.getIdentifiers(getCurrentUser()); + } + + @Override + public void add(ActiveConnection object) throws GuacamoleException { + activeConnectionService.createObject(getCurrentUser(), object); + } + + @Override + public void update(ActiveConnection object) throws GuacamoleException { + TrackedActiveConnection connection = (TrackedActiveConnection) object; + activeConnectionService.updateObject(getCurrentUser(), connection); + } + + @Override + public void remove(String identifier) throws GuacamoleException { + activeConnectionService.deleteObject(getCurrentUser(), identifier); + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/ActiveConnectionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/ActiveConnectionService.java new file mode 100644 index 000000000..41eceef60 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/ActiveConnectionService.java @@ -0,0 +1,151 @@ +/* + * 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.activeconnection; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; +import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; +import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.GuacamoleSecurityException; +import org.glyptodon.guacamole.auth.jdbc.base.DirectoryObjectService; +import org.glyptodon.guacamole.auth.jdbc.tunnel.ActiveConnectionRecord; +import org.glyptodon.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService; +import org.glyptodon.guacamole.net.GuacamoleTunnel; +import org.glyptodon.guacamole.net.auth.ActiveConnection; + +/** + * Service which provides convenience methods for creating, retrieving, and + * manipulating active connections. + * + * @author Michael Jumper + */ +public class ActiveConnectionService + implements DirectoryObjectService { + + /** + * Service for creating and tracking tunnels. + */ + @Inject + private GuacamoleTunnelService tunnelService; + + /** + * Provider for active connections. + */ + @Inject + private Provider trackedActiveConnectionProvider; + + @Override + public TrackedActiveConnection retrieveObject(AuthenticatedUser user, + String identifier) throws GuacamoleException { + + // Only administrators may retrieve active connections + if (!user.getUser().isAdministrator()) + throw new GuacamoleSecurityException("Permission denied."); + + // Retrieve record associated with requested connection + ActiveConnectionRecord record = tunnelService.getActiveConnection(user, identifier); + if (record == null) + return null; + + // Return tracked active connection using retrieved record + TrackedActiveConnection activeConnection = trackedActiveConnectionProvider.get(); + activeConnection.init(user, record); + return activeConnection; + + } + + @Override + public Collection retrieveObjects(AuthenticatedUser user, + Collection identifiers) throws GuacamoleException { + + // Build list of all active connections with given identifiers + Collection activeConnections = new ArrayList(identifiers.size()); + for (String identifier : identifiers) { + + // Add connection to list if it exists + TrackedActiveConnection activeConnection = retrieveObject(user, identifier); + if (activeConnection != null) + activeConnections.add(activeConnection); + + } + + return activeConnections; + + } + + @Override + public void deleteObject(AuthenticatedUser user, String identifier) + throws GuacamoleException { + + // Close connection, if it exists (and we have permission) + ActiveConnection activeConnection = retrieveObject(user, identifier); + if (activeConnection != null) { + + // Close connection if not already closed + GuacamoleTunnel tunnel = activeConnection.getTunnel(); + if (tunnel != null && tunnel.isOpen()) + tunnel.close(); + + } + + } + + @Override + public Set getIdentifiers(AuthenticatedUser user) + throws GuacamoleException { + + // Retrieve all visible connections (permissions enforced by tunnel service) + Collection records = tunnelService.getActiveConnections(user); + + // Build list of identifiers + Set identifiers = new HashSet(records.size()); + for (ActiveConnectionRecord record : records) + identifiers.add(record.getUUID().toString()); + + return identifiers; + + } + + @Override + public TrackedActiveConnection createObject(AuthenticatedUser user, + ActiveConnection object) throws GuacamoleException { + + // Updating active connections is not implemented + throw new GuacamoleSecurityException("Permission denied."); + + } + + @Override + public void updateObject(AuthenticatedUser user, TrackedActiveConnection object) + throws GuacamoleException { + + // Updating active connections is not implemented + 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/activeconnection/TrackedActiveConnection.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/TrackedActiveConnection.java new file mode 100644 index 000000000..8dc00fe27 --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/TrackedActiveConnection.java @@ -0,0 +1,155 @@ +/* + * 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.activeconnection; + +import java.util.Date; +import org.glyptodon.guacamole.auth.jdbc.base.RestrictedObject; +import org.glyptodon.guacamole.auth.jdbc.tunnel.ActiveConnectionRecord; +import org.glyptodon.guacamole.auth.jdbc.user.AuthenticatedUser; +import org.glyptodon.guacamole.net.GuacamoleTunnel; +import org.glyptodon.guacamole.net.auth.ActiveConnection; + +/** + * An implementation of the ActiveConnection object which has an associated + * ActiveConnectionRecord. + * + * @author Michael Jumper + */ +public class TrackedActiveConnection extends RestrictedObject implements ActiveConnection { + + /** + * The identifier of this active connection. + */ + private String identifier; + + /** + * The identifier of the associated connection. + */ + private String connectionIdentifier; + + /** + * The date and time this active connection began. + */ + private Date startDate; + + /** + * The remote host that initiated this connection. + */ + private String remoteHost; + + /** + * The username of the user that initiated this connection. + */ + private String username; + + /** + * The underlying GuacamoleTunnel. + */ + private GuacamoleTunnel tunnel; + + /** + * Initializes this TrackedActiveConnection, copying the data associated + * with the given active connection record. + * + * @param currentUser + * The user that created or retrieved this object. + * + * @param activeConnectionRecord + * The active connection record to copy. + */ + public void init(AuthenticatedUser currentUser, + ActiveConnectionRecord activeConnectionRecord) { + + super.init(currentUser); + + // Copy all data from given record + this.connectionIdentifier = activeConnectionRecord.getConnection().getIdentifier(); + this.identifier = activeConnectionRecord.getUUID().toString(); + this.remoteHost = activeConnectionRecord.getRemoteHost(); + this.startDate = activeConnectionRecord.getStartDate(); + this.tunnel = activeConnectionRecord.getTunnel(); + this.username = activeConnectionRecord.getUsername(); + + } + + @Override + public String getIdentifier() { + return identifier; + } + + @Override + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + @Override + public String getConnectionIdentifier() { + return connectionIdentifier; + } + + @Override + public void setConnectionIdentifier(String connnectionIdentifier) { + this.connectionIdentifier = connnectionIdentifier; + } + + @Override + public Date getStartDate() { + return startDate; + } + + @Override + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + @Override + public String getRemoteHost() { + return remoteHost; + } + + @Override + public void setRemoteHost(String remoteHost) { + this.remoteHost = remoteHost; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public void setUsername(String username) { + this.username = username; + } + + @Override + public GuacamoleTunnel getTunnel() { + return tunnel; + } + + @Override + public void setTunnel(GuacamoleTunnel tunnel) { + this.tunnel = tunnel; + } + +} diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/package-info.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/package-info.java new file mode 100644 index 000000000..018e6303f --- /dev/null +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/activeconnection/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. + */ + +/** + * Classes related to currently-active connections. + */ +package org.glyptodon.guacamole.auth.jdbc.activeconnection; diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java index d00d19d13..83e472c73 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java @@ -24,7 +24,6 @@ package org.glyptodon.guacamole.auth.jdbc.connection; import java.util.Date; -import org.glyptodon.guacamole.net.GuacamoleTunnel; import org.glyptodon.guacamole.net.auth.ConnectionRecord; /** @@ -52,11 +51,6 @@ public class ModeledConnectionRecord implements ConnectionRecord { this.model = model; } - @Override - public String getIdentifier() { - return model.getConnectionIdentifier(); - } - @Override public Date getStartDate() { return model.getStartDate(); @@ -82,9 +76,4 @@ public class ModeledConnectionRecord implements ConnectionRecord { return false; } - @Override - public GuacamoleTunnel getTunnel() { - return null; - } - } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java index 94521f51d..10adde197 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/AbstractGuacamoleTunnelService.java @@ -49,7 +49,6 @@ import org.glyptodon.guacamole.net.GuacamoleSocket; import org.glyptodon.guacamole.net.GuacamoleTunnel; import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionGroup; -import org.glyptodon.guacamole.net.auth.ConnectionRecord; import org.glyptodon.guacamole.protocol.ConfiguredGuacamoleSocket; import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; import org.glyptodon.guacamole.protocol.GuacamoleConfiguration; @@ -100,8 +99,8 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS /** * All active connections through the tunnel having a given UUID. */ - private final Map activeTunnels = - new ConcurrentHashMap(); + private final Map activeTunnels = + new ConcurrentHashMap(); /** * All active connections to a connection having a given identifier. @@ -446,7 +445,7 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS } @Override - public Collection getActiveConnections(AuthenticatedUser user) + public Collection getActiveConnections(AuthenticatedUser user) throws GuacamoleException { // Only administrators may see all active connections @@ -458,7 +457,7 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS } @Override - public ConnectionRecord getActiveConnection(AuthenticatedUser user, + public ActiveConnectionRecord getActiveConnection(AuthenticatedUser user, String tunnelUUID) throws GuacamoleException { // Only administrators may see all active connections @@ -482,7 +481,7 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS } @Override - public Collection getActiveConnections(Connection connection) { + public Collection getActiveConnections(Connection connection) { return activeConnections.get(connection.getIdentifier()); } @@ -507,7 +506,7 @@ public abstract class AbstractGuacamoleTunnelService implements GuacamoleTunnelS } @Override - public Collection getActiveConnections(ConnectionGroup connectionGroup) { + public Collection getActiveConnections(ConnectionGroup connectionGroup) { // If not a balancing group, assume no connections if (connectionGroup.getType() != ConnectionGroup.Type.BALANCING) diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ActiveConnectionMultimap.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ActiveConnectionMultimap.java index a0590333d..4dd011622 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ActiveConnectionMultimap.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ActiveConnectionMultimap.java @@ -28,8 +28,6 @@ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; -import org.glyptodon.guacamole.net.auth.ConnectionRecord; - /** * Mapping of object identifiers to lists of connection records. Records are @@ -44,8 +42,8 @@ public class ActiveConnectionMultimap { /** * All active connections to a connection having a given identifier. */ - private final Map> records = - new HashMap>(); + private final Map> records = + new HashMap>(); /** * Stores the given connection record in the list of active connections @@ -57,13 +55,13 @@ public class ActiveConnectionMultimap { * @param record * The record associated with the active connection. */ - public void put(String identifier, ConnectionRecord record) { + public void put(String identifier, ActiveConnectionRecord record) { synchronized (records) { // Get set of active connection records, creating if necessary - Set connections = records.get(identifier); + Set connections = records.get(identifier); if (connections == null) { - connections = Collections.synchronizedSet(Collections.newSetFromMap(new LinkedHashMap())); + connections = Collections.synchronizedSet(Collections.newSetFromMap(new LinkedHashMap())); records.put(identifier, connections); } @@ -83,11 +81,11 @@ public class ActiveConnectionMultimap { * @param record * The record associated with the active connection. */ - public void remove(String identifier, ConnectionRecord record) { + public void remove(String identifier, ActiveConnectionRecord record) { synchronized (records) { // Get set of active connection records - Set connections = records.get(identifier); + Set connections = records.get(identifier); assert(connections != null); // Remove old record @@ -114,11 +112,11 @@ public class ActiveConnectionMultimap { * the given identifier, or an empty collection if there are no such * records. */ - public Collection get(String identifier) { + public Collection get(String identifier) { synchronized (records) { // Get set of active connection records - Collection connections = records.get(identifier); + Collection connections = records.get(identifier); if (connections != null) return Collections.unmodifiableCollection(connections); diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ActiveConnectionRecord.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ActiveConnectionRecord.java index de2bffaf2..6401e705c 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ActiveConnectionRecord.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/ActiveConnectionRecord.java @@ -164,11 +164,6 @@ public class ActiveConnectionRecord implements ConnectionRecord { return balancingGroup != null; } - @Override - public String getIdentifier() { - return connection.getIdentifier(); - } - @Override public Date getStartDate() { return startDate; @@ -200,7 +195,14 @@ public class ActiveConnectionRecord implements ConnectionRecord { } - @Override + /** + * Returns the GuacamoleTunnel currently associated with the active + * connection represented by this connection record. + * + * @return + * The GuacamoleTunnel currently associated with the active connection + * represented by this connection record. + */ public GuacamoleTunnel getTunnel() { return tunnel; } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/GuacamoleTunnelService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/GuacamoleTunnelService.java index f45d31426..0bb78419d 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/GuacamoleTunnelService.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/tunnel/GuacamoleTunnelService.java @@ -30,7 +30,6 @@ import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.net.GuacamoleTunnel; import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionGroup; -import org.glyptodon.guacamole.net.auth.ConnectionRecord; import org.glyptodon.guacamole.protocol.GuacamoleClientInformation; @@ -57,7 +56,7 @@ public interface GuacamoleTunnelService { * If an error occurs while retrieving all active connections, or if * permission is denied. */ - public Collection getActiveConnections(AuthenticatedUser user) + public Collection getActiveConnections(AuthenticatedUser user) throws GuacamoleException; /** @@ -80,7 +79,7 @@ public interface GuacamoleTunnelService { * If an error occurs while retrieving all active connections, or if * permission is denied. */ - public ConnectionRecord getActiveConnection(AuthenticatedUser user, + public ActiveConnectionRecord getActiveConnection(AuthenticatedUser user, String tunnelUUID) throws GuacamoleException; @@ -114,7 +113,7 @@ public interface GuacamoleTunnelService { throws GuacamoleException; /** - * Returns a connection containing connection records representing all + * Returns a collection containing connection records representing all * currently-active connections using the given connection. These records * will have usernames and start dates, but no end date, and will be * sorted in ascending order by start date. @@ -126,7 +125,7 @@ public interface GuacamoleTunnelService { * A collection containing connection records representing all * currently-active connections. */ - public Collection getActiveConnections(Connection connection); + public Collection getActiveConnections(Connection connection); /** * Creates a socket for the given user which connects to the given @@ -171,6 +170,6 @@ public interface GuacamoleTunnelService { * A collection containing connection records representing all * currently-active connections. */ - public Collection getActiveConnections(ConnectionGroup connectionGroup); + public Collection getActiveConnections(ConnectionGroup connectionGroup); } diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/ModeledUser.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/ModeledUser.java index 2ec2ca0b2..96c88793e 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/ModeledUser.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/ModeledUser.java @@ -28,6 +28,7 @@ import org.glyptodon.guacamole.auth.jdbc.security.PasswordEncryptionService; import org.glyptodon.guacamole.auth.jdbc.security.SaltService; import org.glyptodon.guacamole.auth.jdbc.permission.SystemPermissionService; import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.GuacamoleUnsupportedException; import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionGroupPermissionService; import org.glyptodon.guacamole.auth.jdbc.permission.ConnectionPermissionService; import org.glyptodon.guacamole.auth.jdbc.permission.UserPermissionService; @@ -160,6 +161,12 @@ public class ModeledUser extends ModeledDirectoryObject implements Us return connectionGroupPermissionService.getPermissionSet(getCurrentUser(), this); } + @Override + public ObjectPermissionSet getActiveConnectionPermissions() + throws GuacamoleException { + throw new GuacamoleUnsupportedException("STUB"); + } + @Override public ObjectPermissionSet getUserPermissions() throws GuacamoleException { diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserContext.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserContext.java index ae06013ec..0b496240b 100644 --- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserContext.java +++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/glyptodon/guacamole/auth/jdbc/user/UserContext.java @@ -28,14 +28,12 @@ import org.glyptodon.guacamole.auth.jdbc.connectiongroup.ConnectionGroupDirector import org.glyptodon.guacamole.auth.jdbc.connection.ConnectionDirectory; import com.google.inject.Inject; import com.google.inject.Provider; -import java.util.ArrayList; -import java.util.Collection; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.auth.jdbc.base.RestrictedObject; -import org.glyptodon.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService; +import org.glyptodon.guacamole.auth.jdbc.activeconnection.ActiveConnectionDirectory; +import org.glyptodon.guacamole.net.auth.ActiveConnection; import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionGroup; -import org.glyptodon.guacamole.net.auth.ConnectionRecord; import org.glyptodon.guacamole.net.auth.Directory; import org.glyptodon.guacamole.net.auth.User; @@ -49,12 +47,6 @@ import org.glyptodon.guacamole.net.auth.User; public class UserContext extends RestrictedObject implements org.glyptodon.guacamole.net.auth.UserContext { - /** - * Service for creating and tracking tunnels. - */ - @Inject - private GuacamoleTunnelService tunnelService; - /** * User directory restricted by the permissions of the user associated * with this context. @@ -76,6 +68,13 @@ public class UserContext extends RestrictedObject @Inject private ConnectionGroupDirectory connectionGroupDirectory; + /** + * ActiveConnection directory restricted by the permissions of the user + * associated with this context. + */ + @Inject + private ActiveConnectionDirectory activeConnectionDirectory; + /** * Provider for creating the root group. */ @@ -91,6 +90,7 @@ public class UserContext extends RestrictedObject userDirectory.init(currentUser); connectionDirectory.init(currentUser); connectionGroupDirectory.init(currentUser); + activeConnectionDirectory.init(currentUser); } @@ -114,6 +114,12 @@ public class UserContext extends RestrictedObject return connectionGroupDirectory; } + @Override + public Directory getActiveConnectionDirectory() + throws GuacamoleException { + return activeConnectionDirectory; + } + @Override public ConnectionGroup getRootConnectionGroup() throws GuacamoleException { @@ -124,29 +130,4 @@ public class UserContext extends RestrictedObject } - @Override - public Collection getActiveConnections() - throws GuacamoleException { - return tunnelService.getActiveConnections(getCurrentUser()); - } - - @Override - public Collection getActiveConnections(Collection tunnelUUIDs) - throws GuacamoleException { - - // Look up active connections for each given tunnel UUID - Collection records = new ArrayList(tunnelUUIDs.size()); - for (String tunnelUUID : tunnelUUIDs) { - - // Add corresponding record only if it exists - ConnectionRecord record = tunnelService.getActiveConnection(getCurrentUser(), tunnelUUID); - if (record != null) - records.add(record); - - } - - return records; - - } - } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/AbstractActiveConnection.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/AbstractActiveConnection.java new file mode 100644 index 000000000..7ce50aa61 --- /dev/null +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/AbstractActiveConnection.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.net.auth; + +import java.util.Date; +import org.glyptodon.guacamole.net.GuacamoleTunnel; + +public abstract class AbstractActiveConnection implements ActiveConnection { + + /** + * The identifier of this active connection. + */ + private String identifier; + + /** + * The identifier of the associated connection. + */ + private String connectionIdentifier; + + /** + * The date and time this active connection began. + */ + private Date startDate; + + /** + * The remote host that initiated this connection. + */ + private String remoteHost; + + /** + * The username of the user that initiated this connection. + */ + private String username; + + /** + * The underlying GuacamoleTunnel. + */ + private GuacamoleTunnel tunnel; + + @Override + public String getIdentifier() { + return identifier; + } + + @Override + public void setIdentifier(String identifier) { + this.identifier = identifier; + } + + @Override + public String getConnectionIdentifier() { + return connectionIdentifier; + } + + @Override + public void setConnectionIdentifier(String connnectionIdentifier) { + this.connectionIdentifier = connnectionIdentifier; + } + + @Override + public Date getStartDate() { + return startDate; + } + + @Override + public void setStartDate(Date startDate) { + this.startDate = startDate; + } + + @Override + public String getRemoteHost() { + return remoteHost; + } + + @Override + public void setRemoteHost(String remoteHost) { + this.remoteHost = remoteHost; + } + + @Override + public String getUsername() { + return username; + } + + @Override + public void setUsername(String username) { + this.username = username; + } + + @Override + public GuacamoleTunnel getTunnel() { + return tunnel; + } + + @Override + public void setTunnel(GuacamoleTunnel tunnel) { + this.tunnel = tunnel; + } + +} diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ActiveConnection.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ActiveConnection.java new file mode 100644 index 000000000..8258e59db --- /dev/null +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ActiveConnection.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2015 Glyptodon LLC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.glyptodon.guacamole.net.auth; + +import java.util.Date; +import org.glyptodon.guacamole.net.GuacamoleTunnel; + +/** + * A pairing of username and GuacamoleTunnel representing an active usage of a + * particular connection. + * + * @author Michael Jumper + */ +public interface ActiveConnection extends Identifiable { + + /** + * Returns the identifier of the connection being actively used. + * + * @return + * The identifier of the connection being actively used. + */ + String getConnectionIdentifier(); + + /** + * Sets the identifier of the connection being actively used. + * + * @param connnectionIdentifier + * The identifier of the connection being actively used. + */ + void setConnectionIdentifier(String connnectionIdentifier); + + /** + * Returns the date and time the connection began. + * + * @return + * The date and time the connection began. + */ + Date getStartDate(); + + /** + * Sets the date and time the connection began. + * + * @param startDate + * The date and time the connection began. + */ + void setStartDate(Date startDate); + + /** + * Returns the hostname or IP address of the remote host that initiated the + * connection, if known. If the hostname or IP address is not known, null + * is returned. + * + * @return + * The hostname or IP address of the remote host, or null if this + * information is not available. + */ + String getRemoteHost(); + + /** + * Sets the hostname or IP address of the remote host that initiated the + * connection. + * + * @param remoteHost + * The hostname or IP address of the remote host, or null if this + * information is not available. + */ + void setRemoteHost(String remoteHost); + + /** + * Returns the name of the user who is using this connection. + * + * @return + * The name of the user who is using this connection. + */ + String getUsername(); + + /** + * Sets the name of the user who is using this connection. + * + * @param username + * The name of the user who is using this connection. + */ + void setUsername(String username); + + /** + * Returns the connected GuacamoleTunnel being used. This may be null if + * access to the underlying tunnel is denied. + * + * @return + * The connected GuacamoleTunnel, or null if permission is denied. + */ + GuacamoleTunnel getTunnel(); + + /** + * Sets the connected GuacamoleTunnel being used. + * + * @param tunnel + * The connected GuacamoleTunnel, or null if permission is denied. + */ + void setTunnel(GuacamoleTunnel tunnel); + +} diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionRecord.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionRecord.java index a4e2fcbe5..bb43565d5 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionRecord.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/ConnectionRecord.java @@ -23,7 +23,6 @@ package org.glyptodon.guacamole.net.auth; import java.util.Date; -import org.glyptodon.guacamole.net.GuacamoleTunnel; /** * A logging record describing when a user started and ended usage of a @@ -33,16 +32,6 @@ import org.glyptodon.guacamole.net.GuacamoleTunnel; */ public interface ConnectionRecord { - /** - * Returns the identifier of the connection associated with this connection - * record. - * - * @return - * The identifier of the connection associated with this connection - * record. - */ - public String getIdentifier(); - /** * Returns the date and time the connection began. * @@ -87,15 +76,4 @@ public interface ConnectionRecord { */ public boolean isActive(); - /** - * Returns the connected GuacamoleTunnel of the connection associated with - * this record, if any. If the connection is not active, or access to - * the socket is denied, null is returned. - * - * @return - * The connected GuacamoleTunnel, if any, or null if the connection is - * not active or permission is denied. - */ - public GuacamoleTunnel getTunnel(); - } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/User.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/User.java index 09e4c2e78..267ad1f0f 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/User.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/User.java @@ -92,6 +92,21 @@ public interface User extends Identifiable { ObjectPermissionSet getConnectionGroupPermissions() throws GuacamoleException; + /** + * Returns all permissions given to this user regarding currently-active + * connections. + * + * @return + * An ObjectPermissionSet of all active connection permissions granted + * to this user. + * + * @throws GuacamoleException + * If an error occurs while retrieving permissions, or if reading all + * permissions is not allowed. + */ + ObjectPermissionSet getActiveConnectionPermissions() + throws GuacamoleException; + /** * Returns all user permissions given to this user. * diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/UserContext.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/UserContext.java index bad5901fe..38538bce1 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/UserContext.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/UserContext.java @@ -22,7 +22,6 @@ package org.glyptodon.guacamole.net.auth; -import java.util.Collection; import org.glyptodon.guacamole.GuacamoleException; /** @@ -83,6 +82,21 @@ public interface UserContext { Directory getConnectionGroupDirectory() throws GuacamoleException; + /** + * Retrieves a Directory which can be used to view and manipulate + * active connections, but only as allowed by the permissions given to the + * user. + * + * @return + * A Directory whose operations are bound by the permissions of the + * user. + * + * @throws GuacamoleException + * If an error occurs while creating the Directory. + */ + Directory getActiveConnectionDirectory() + throws GuacamoleException; + /** * Retrieves a connection group which can be used to view and manipulate * connections, but only as allowed by the permissions given to the user of @@ -96,41 +110,4 @@ public interface UserContext { */ ConnectionGroup getRootConnectionGroup() throws GuacamoleException; - /** - * Returns a collection of connection records associated with all active - * connections to which the current user has access. For an administrative - * user, this may include connections associated with other users. - * - * @return - * A collection of all connection records associated with active - * connections to which the current user has access. - * - * @throws GuacamoleException - * If an error occurs while reading active connection records, or if - * permission is denied. - */ - Collection getActiveConnections() - throws GuacamoleException; - - /** - * Returns the connection records associated with the active connections - * having the tunnels with the given UUIDs. An active connection will only - * be returned if the current user has access. - * - * @param tunnelUUIDs - * The UUIDs of the tunnels whose associated connection records should - * be returned. - * - * @return - * A collection of all connection records associated with the active - * connections having the tunnels with the given UUIDs, if any, or an - * empty collection if no such connections exist. - * - * @throws GuacamoleException - * If an error occurs while reading active connection records, or if - * permission is denied. - */ - Collection getActiveConnections(Collection tunnelUUIDs) - throws GuacamoleException; - } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java index fa0899fa2..a9da2e939 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUser.java @@ -130,4 +130,10 @@ public class SimpleUser extends AbstractUser { return new SimpleObjectPermissionSet(); } + @Override + public ObjectPermissionSet getActiveConnectionPermissions() + throws GuacamoleException { + return new SimpleObjectPermissionSet(); + } + } diff --git a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java index 3f6b45fe2..4ebc2d6a3 100644 --- a/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java +++ b/guacamole-ext/src/main/java/org/glyptodon/guacamole/net/auth/simple/SimpleUserContext.java @@ -28,9 +28,9 @@ import java.util.Collections; import java.util.Map; import java.util.UUID; import org.glyptodon.guacamole.GuacamoleException; +import org.glyptodon.guacamole.net.auth.ActiveConnection; import org.glyptodon.guacamole.net.auth.Connection; import org.glyptodon.guacamole.net.auth.ConnectionGroup; -import org.glyptodon.guacamole.net.auth.ConnectionRecord; import org.glyptodon.guacamole.net.auth.Directory; import org.glyptodon.guacamole.net.auth.User; import org.glyptodon.guacamole.net.auth.UserContext; @@ -169,15 +169,9 @@ public class SimpleUserContext implements UserContext { } @Override - public Collection getActiveConnections() + public Directory getActiveConnectionDirectory() throws GuacamoleException { - return Collections.EMPTY_LIST; - } - - @Override - public Collection getActiveConnections(Collection tunnelUUID) - throws GuacamoleException { - return Collections.EMPTY_LIST; + return new SimpleDirectory(); } } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletModule.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletModule.java index a2f0232f3..91cade593 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletModule.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/RESTServletModule.java @@ -31,7 +31,7 @@ import org.glyptodon.guacamole.net.basic.rest.clipboard.ClipboardRESTService; import org.glyptodon.guacamole.net.basic.rest.connection.ConnectionRESTService; import org.glyptodon.guacamole.net.basic.rest.connectiongroup.ConnectionGroupRESTService; import org.glyptodon.guacamole.net.basic.rest.protocol.ProtocolRESTService; -import org.glyptodon.guacamole.net.basic.rest.tunnel.TunnelRESTService; +import org.glyptodon.guacamole.net.basic.rest.activeconnection.ActiveConnectionRESTService; import org.glyptodon.guacamole.net.basic.rest.user.UserRESTService; /** @@ -51,7 +51,7 @@ public class RESTServletModule extends ServletModule { bind(ProtocolRESTService.class); bind(UserRESTService.class); bind(TokenRESTService.class); - bind(TunnelRESTService.class); + bind(ActiveConnectionRESTService.class); // Set up the servlet and JSON mappings bind(GuiceContainer.class); diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/tunnel/APITunnel.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/activeconnection/APIActiveConnection.java similarity index 66% rename from guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/tunnel/APITunnel.java rename to guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/activeconnection/APIActiveConnection.java index ca1a0604c..2065c39f6 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/tunnel/APITunnel.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/activeconnection/APIActiveConnection.java @@ -20,22 +20,29 @@ * THE SOFTWARE. */ -package org.glyptodon.guacamole.net.basic.rest.tunnel; +package org.glyptodon.guacamole.net.basic.rest.activeconnection; import java.util.Date; -import org.glyptodon.guacamole.net.auth.ConnectionRecord; +import org.glyptodon.guacamole.net.auth.ActiveConnection; /** - * Tunnel-related information which may be exposed through the REST endpoints. + * Information related to active connections which may be exposed through the + * REST endpoints. * * @author Michael Jumper */ -public class APITunnel { +public class APIActiveConnection { /** - * The identifier of the connection associated with this tunnel. + * The identifier of the active connection itself. */ private final String identifier; + + /** + * The identifier of the connection associated with this + * active connection. + */ + private final String connectionIdentifier; /** * The date and time the connection began. @@ -53,26 +60,18 @@ public class APITunnel { private final String username; /** - * The UUID of the tunnel. - */ - private final String uuid; - - /** - * Creates a new APITunnel, copying the information from the given - * connection record. + * Creates a new APIActiveConnection, copying the information from the given + * active connection. * - * @param record - * The record to copy data from. - * - * @param uuid - * The UUID of the associated GuacamoleTunnel. + * @param connection + * The active connection to copy data from. */ - public APITunnel(ConnectionRecord record, String uuid) { - this.identifier = record.getIdentifier(); - this.startDate = record.getStartDate(); - this.remoteHost = record.getRemoteHost(); - this.username = record.getUsername(); - this.uuid = uuid; + public APIActiveConnection(ActiveConnection connection) { + this.identifier = connection.getIdentifier(); + this.connectionIdentifier = connection.getConnectionIdentifier(); + this.startDate = connection.getStartDate(); + this.remoteHost = connection.getRemoteHost(); + this.username = connection.getUsername(); } /** @@ -81,8 +80,8 @@ public class APITunnel { * @return * The identifier of the connection associated with this tunnel. */ - public String getIdentifier() { - return identifier; + public String getConnectionIdentifier() { + return connectionIdentifier; } /** @@ -117,14 +116,15 @@ public class APITunnel { } /** - * Returns the UUID of the underlying Guacamole tunnel. Absolutely every - * Guacamole tunnel has an associated UUID. + * Returns the identifier of the active connection itself. This is + * distinct from the connection identifier, and uniquely identifies a + * specific use of a connection. * * @return - * The UUID of the underlying Guacamole tunnel. + * The identifier of the active connection. */ - public String getUUID() { - return uuid; + public String getIdentifier() { + return identifier; } } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/tunnel/TunnelRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/activeconnection/ActiveConnectionRESTService.java similarity index 51% rename from guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/tunnel/TunnelRESTService.java rename to guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/activeconnection/ActiveConnectionRESTService.java index 91641eadd..1c4d6cab3 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/tunnel/TunnelRESTService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/activeconnection/ActiveConnectionRESTService.java @@ -20,10 +20,9 @@ * THE SOFTWARE. */ -package org.glyptodon.guacamole.net.basic.rest.tunnel; +package org.glyptodon.guacamole.net.basic.rest.activeconnection; import com.google.inject.Inject; -import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -37,9 +36,14 @@ import javax.ws.rs.core.MediaType; import org.glyptodon.guacamole.GuacamoleClientException; import org.glyptodon.guacamole.GuacamoleException; import org.glyptodon.guacamole.GuacamoleUnsupportedException; -import org.glyptodon.guacamole.net.GuacamoleTunnel; -import org.glyptodon.guacamole.net.auth.ConnectionRecord; +import org.glyptodon.guacamole.net.auth.ActiveConnection; +import org.glyptodon.guacamole.net.auth.Directory; +import org.glyptodon.guacamole.net.auth.User; import org.glyptodon.guacamole.net.auth.UserContext; +import org.glyptodon.guacamole.net.auth.permission.ObjectPermission; +import org.glyptodon.guacamole.net.auth.permission.ObjectPermissionSet; +import org.glyptodon.guacamole.net.auth.permission.SystemPermission; +import org.glyptodon.guacamole.net.auth.permission.SystemPermissionSet; import org.glyptodon.guacamole.net.basic.rest.APIPatch; import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure; import org.glyptodon.guacamole.net.basic.rest.PATCH; @@ -52,15 +56,15 @@ import org.slf4j.LoggerFactory; * * @author Michael Jumper */ -@Path("/tunnels") +@Path("/activeConnections") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) -public class TunnelRESTService { +public class ActiveConnectionRESTService { /** * Logger for this class. */ - private static final Logger logger = LoggerFactory.getLogger(TunnelRESTService.class); + private static final Logger logger = LoggerFactory.getLogger(ActiveConnectionRESTService.class); /** * A service for authenticating users from auth tokens. @@ -69,61 +73,78 @@ public class TunnelRESTService { private AuthenticationService authenticationService; /** - * Retrieves the tunnels of all active connections visible to the current - * user. + * Gets a list of active connections in the system, filtering the returned + * list by the given permissions, if specified. * * @param authToken * The authentication token that is used to authenticate the user * performing the operation. * + * @param permissions + * The set of permissions to filter with. A user must have one or more + * of these permissions for a user to appear in the result. + * If null, no filtering will be performed. + * * @return - * A map of the tunnels of all active connections visible to the - * current user, where the key of each entry is the tunnel's UUID. - * + * A list of all active connections. If a permission was specified, + * this list will contain only those active connections for which the + * current user has that permission. + * * @throws GuacamoleException - * If an error occurs while retrieving the tunnels. + * If an error is encountered while retrieving active connections. */ @GET - @Path("/") @AuthProviderRESTExposure - public Map getTunnels(@QueryParam("token") String authToken) + public Map getActiveConnections(@QueryParam("token") String authToken, + @QueryParam("permission") List permissions) throws GuacamoleException { UserContext userContext = authenticationService.getUserContext(authToken); + User self = userContext.self(); + + // Do not filter on permissions if no permissions are specified + if (permissions != null && permissions.isEmpty()) + permissions = null; - // Retrieve all active tunnels - Map apiTunnels = new HashMap(); - for (ConnectionRecord record : userContext.getActiveConnections()) { + // An admin user has access to any user + SystemPermissionSet systemPermissions = self.getSystemPermissions(); + boolean isAdmin = systemPermissions.hasPermission(SystemPermission.Type.ADMINISTER); - // Locate associated tunnel and UUID - GuacamoleTunnel tunnel = record.getTunnel(); - if (tunnel != null) { - APITunnel apiTunnel = new APITunnel(record, tunnel.getUUID().toString()); - apiTunnels.put(apiTunnel.getUUID(), apiTunnel); - } + // Get the directory + Directory activeConnectionDirectory = userContext.getActiveConnectionDirectory(); + // Filter users, if requested + Collection activeConnectionIdentifiers = activeConnectionDirectory.getIdentifiers(); + if (!isAdmin && permissions != null) { + ObjectPermissionSet userPermissions = self.getUserPermissions(); + activeConnectionIdentifiers = userPermissions.getAccessibleObjects(permissions, activeConnectionIdentifiers); } + + // Retrieve all active connections , converting to API active connections + Map apiActiveConnections = new HashMap(); + for (ActiveConnection activeConnection : activeConnectionDirectory.getAll(activeConnectionIdentifiers)) + apiActiveConnections.put(activeConnection.getIdentifier(), new APIActiveConnection(activeConnection)); - return apiTunnels; + return apiActiveConnections; } /** - * Applies the given tunnel patches. This operation currently only supports - * deletion of tunnels through the "remove" patch operation. Deleting a - * tunnel effectively closing the tunnel and kills the associated - * connection. The path of each patch operation is of the form "/UUID" - * where UUID is the UUID of the tunnel being modified. + * Applies the given active connection patches. This operation currently + * only supports deletion of active connections through the "remove" patch + * operation. Deleting an active connection effectively kills the + * connection. The path of each patch operation is of the form "/ID" + * where ID is the identifier of the active connection being modified. * * @param authToken * The authentication token that is used to authenticate the user * performing the operation. * * @param patches - * The tunnel patches to apply for this request. + * The active connection patches to apply for this request. * * @throws GuacamoleException - * If an error occurs while deleting the tunnels. + * If an error occurs while deleting the active connections. */ @PATCH @Path("/") @@ -131,37 +152,28 @@ public class TunnelRESTService { public void patchTunnels(@QueryParam("token") String authToken, List> patches) throws GuacamoleException { - // Attempt to get all requested tunnels UserContext userContext = authenticationService.getUserContext(authToken); - // Build list of tunnels to delete - Collection tunnelUUIDs = new ArrayList(patches.size()); + // Get the directory + Directory activeConnectionDirectory = userContext.getActiveConnectionDirectory(); + + // Close each connection listed for removal for (APIPatch patch : patches) { // Only remove is supported if (patch.getOp() != APIPatch.Operation.remove) - throw new GuacamoleUnsupportedException("Only the \"remove\" operation is supported when patching tunnels."); + throw new GuacamoleUnsupportedException("Only the \"remove\" operation is supported when patching active connections."); // Retrieve and validate path String path = patch.getPath(); if (!path.startsWith("/")) throw new GuacamoleClientException("Patch paths must start with \"/\"."); - - // Add UUID - tunnelUUIDs.add(path.substring(1)); + + // Close connection + activeConnectionDirectory.remove(path.substring(1)); } - // Close each tunnel, if not already closed - Collection records = userContext.getActiveConnections(tunnelUUIDs); - for (ConnectionRecord record : records) { - - GuacamoleTunnel tunnel = record.getTunnel(); - if (tunnel != null && tunnel.isOpen()) - tunnel.close(); - - } - } } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/permission/APIPermissionSet.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/permission/APIPermissionSet.java index 697641086..d04dd0bb5 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/permission/APIPermissionSet.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/permission/APIPermissionSet.java @@ -56,6 +56,12 @@ public class APIPermissionSet { private Map> connectionGroupPermissions = new HashMap>(); + /** + * Map of active connection ID to the set of granted permissions. + */ + private Map> activeConnectionPermissions = + new HashMap>(); + /** * Map of user ID to the set of granted permissions. */ @@ -149,10 +155,11 @@ public class APIPermissionSet { public APIPermissionSet(User user) throws GuacamoleException { // Add all permissions from the provided user - addSystemPermissions(systemPermissions, user.getSystemPermissions()); - addObjectPermissions(connectionPermissions, user.getConnectionPermissions()); - addObjectPermissions(connectionGroupPermissions, user.getConnectionGroupPermissions()); - addObjectPermissions(userPermissions, user.getUserPermissions()); + addSystemPermissions(systemPermissions, user.getSystemPermissions()); + addObjectPermissions(connectionPermissions, user.getConnectionPermissions()); + addObjectPermissions(connectionGroupPermissions, user.getConnectionGroupPermissions()); + addObjectPermissions(activeConnectionPermissions, user.getActiveConnectionPermissions()); + addObjectPermissions(userPermissions, user.getUserPermissions()); } @@ -186,6 +193,21 @@ public class APIPermissionSet { return connectionGroupPermissions; } + /** + * Returns a map of active connection IDs to the set of permissions granted + * for that active connection. If no permissions are granted to a particular + * active connection, its ID will not be present as a key in the map. This + * map is mutable, and changes to this map will affect the permission set + * directly. + * + * @return + * A map of active connection IDs to the set of permissions granted for + * that active connection. + */ + public Map> getActiveConnectionPermissions() { + return activeConnectionPermissions; + } + /** * Returns a map of user IDs to the set of permissions granted for that * user. If no permissions are granted to a particular user, its ID will @@ -238,6 +260,19 @@ public class APIPermissionSet { this.connectionGroupPermissions = connectionGroupPermissions; } + /** + * Replaces the current map of active connection permissions with the give + * map, which must map active connection ID to its corresponding set of + * granted permissions. If an active connection has no permissions, its ID + * must not be present as a key in the map. + * + * @param activeConnectionPermissions + * The map which must replace the currently-stored map of permissions. + */ + public void setActiveConnectionPermissions(Map> activeConnectionPermissions) { + this.activeConnectionPermissions = activeConnectionPermissions; + } + /** * Replaces the current map of user permissions with the given map, which * must map user ID to its corresponding set of granted permissions. If a diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/APIUserWrapper.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/APIUserWrapper.java index 52e5e707d..c1bc8b58a 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/APIUserWrapper.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/APIUserWrapper.java @@ -95,4 +95,10 @@ public class APIUserWrapper implements User { throw new GuacamoleUnsupportedException("APIUserWrapper does not provide permission access."); } + @Override + public ObjectPermissionSet getActiveConnectionPermissions() + throws GuacamoleException { + throw new GuacamoleUnsupportedException("APIUserWrapper does not provide permission access."); + } + } diff --git a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java index 0167cf860..85f124476 100644 --- a/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java +++ b/guacamole/src/main/java/org/glyptodon/guacamole/net/basic/rest/user/UserRESTService.java @@ -92,6 +92,12 @@ public class UserRESTService { */ private static final String CONNECTION_GROUP_PERMISSION_PATCH_PATH_PREFIX = "/connectionGroupPermissions/"; + /** + * The prefix of any path within an operation of a JSON patch which + * modifies the permissions of a user regarding a specific active connection. + */ + private static final String ACTIVE_CONNECTION_PERMISSION_PATCH_PATH_PREFIX = "/activeConnectionPermissions/"; + /** * The prefix of any path within an operation of a JSON patch which * modifies the permissions of a user regarding another, specific user. @@ -503,10 +509,11 @@ public class UserRESTService { throw new GuacamoleResourceNotFoundException("No such user: \"" + username + "\""); // Permission patches for all types of permissions - PermissionSetPatch connectionPermissionPatch = new PermissionSetPatch(); - PermissionSetPatch connectionGroupPermissionPatch = new PermissionSetPatch(); - PermissionSetPatch userPermissionPatch = new PermissionSetPatch(); - PermissionSetPatch systemPermissionPatch = new PermissionSetPatch(); + PermissionSetPatch connectionPermissionPatch = new PermissionSetPatch(); + PermissionSetPatch connectionGroupPermissionPatch = new PermissionSetPatch(); + PermissionSetPatch activeConnectionPermissionPatch = new PermissionSetPatch(); + PermissionSetPatch userPermissionPatch = new PermissionSetPatch(); + PermissionSetPatch systemPermissionPatch = new PermissionSetPatch(); // Apply all patch operations individually for (APIPatch patch : patches) { @@ -539,6 +546,19 @@ public class UserRESTService { } + // Create active connection permission if path has active connection prefix + else if (path.startsWith(ACTIVE_CONNECTION_PERMISSION_PATCH_PATH_PREFIX)) { + + // Get identifier and type from patch operation + String identifier = path.substring(ACTIVE_CONNECTION_PERMISSION_PATCH_PATH_PREFIX.length()); + ObjectPermission.Type type = ObjectPermission.Type.valueOf(patch.getValue()); + + // Create and update corresponding permission + ObjectPermission permission = new ObjectPermission(type, identifier); + updatePermissionSet(patch.getOp(), activeConnectionPermissionPatch, permission); + + } + // Create user permission if path has user prefix else if (path.startsWith(USER_PERMISSION_PATCH_PATH_PREFIX)) { @@ -573,6 +593,7 @@ public class UserRESTService { // Save the permission changes connectionPermissionPatch.apply(user.getConnectionPermissions()); connectionGroupPermissionPatch.apply(user.getConnectionGroupPermissions()); + activeConnectionPermissionPatch.apply(user.getActiveConnectionPermissions()); userPermissionPatch.apply(user.getUserPermissions()); systemPermissionPatch.apply(user.getSystemPermissions());