mirror of
				https://github.com/gyurix1968/guacamole-client.git
				synced 2025-10-31 00:53:21 +00:00 
			
		
		
		
	GUAC-919: Remove SessionKeepAlive (not needed without HttpSession). Consider sessions to be active so long as they have associated tunnels.
This commit is contained in:
		| @@ -26,7 +26,10 @@ import java.lang.reflect.InvocationTargetException; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| import java.util.Collections; | ||||
| import java.util.Map; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| import org.glyptodon.guacamole.GuacamoleException; | ||||
| import org.glyptodon.guacamole.net.GuacamoleTunnel; | ||||
| import org.glyptodon.guacamole.net.auth.Credentials; | ||||
| import org.glyptodon.guacamole.net.auth.UserContext; | ||||
| import org.glyptodon.guacamole.net.basic.properties.BasicGuacamoleProperties; | ||||
| @@ -60,6 +63,11 @@ public class GuacamoleSession { | ||||
|      */ | ||||
|     private final ClipboardState clipboardState = new ClipboardState(); | ||||
|  | ||||
|     /** | ||||
|      * All currently-active tunnels, indexed by tunnel UUID. | ||||
|      */ | ||||
|     private final Map<String, GuacamoleTunnel> tunnels = new ConcurrentHashMap<String, GuacamoleTunnel>(); | ||||
|  | ||||
|     /** | ||||
|      * Creates a new Guacamole session associated with the given user context. | ||||
|      * | ||||
| @@ -157,5 +165,49 @@ public class GuacamoleSession { | ||||
|     public Collection<Object> getListeners() { | ||||
|         return Collections.unmodifiableCollection(listeners); | ||||
|     } | ||||
|      | ||||
|  | ||||
|     /** | ||||
|      * Returns whether this session has any associated active tunnels. | ||||
|      * | ||||
|      * @return true if this session has any associated active tunnels, | ||||
|      *         false otherwise. | ||||
|      */ | ||||
|     public boolean hasTunnels() { | ||||
|         return !tunnels.isEmpty(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns a map of all active tunnels associated with this session, where | ||||
|      * each key is the String representation of the tunnel's UUID. Changes to | ||||
|      * this map immediately affect the set of tunnels associated with this | ||||
|      * session. A tunnel need not be present here to be used by the user | ||||
|      * associated with this session, but tunnels not in this set will not | ||||
|      * be taken into account when determining whether a session is in use. | ||||
|      * | ||||
|      * @return A map of all active tunnels associated with this session. | ||||
|      */ | ||||
|     public Map<String, GuacamoleTunnel> getTunnels() { | ||||
|         return tunnels; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Associates the given tunnel with this session, such that it is taken | ||||
|      * into account when determining session activity. | ||||
|      * | ||||
|      * @param tunnel The tunnel to associate with this session. | ||||
|      */ | ||||
|     public void addTunnel(GuacamoleTunnel tunnel) { | ||||
|         tunnels.put(tunnel.getUUID().toString(), tunnel); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Disassociates the tunnel having the given UUID from this session. | ||||
|      * | ||||
|      * @param uuid The UUID of the tunnel to disassociate from this session. | ||||
|      * @return true if the tunnel existed and was removed, false otherwise. | ||||
|      */ | ||||
|     public boolean removeTunnel(String uuid) { | ||||
|         return tunnels.remove(uuid) != null; | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -1,68 +0,0 @@ | ||||
| /* | ||||
|  * Copyright (C) 2014 Glyptodon LLC | ||||
|  * | ||||
|  * Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
|  * of this software and associated documentation files (the "Software"), to deal | ||||
|  * in the Software without restriction, including without limitation the rights | ||||
|  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
|  * copies of the Software, and to permit persons to whom the Software is | ||||
|  * furnished to do so, subject to the following conditions: | ||||
|  * | ||||
|  * The above copyright notice and this permission notice shall be included in | ||||
|  * all copies or substantial portions of the Software. | ||||
|  * | ||||
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
|  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
|  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
|  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
|  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
|  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||||
|  * THE SOFTWARE. | ||||
|  */ | ||||
|  | ||||
| package org.glyptodon.guacamole.net.basic; | ||||
|  | ||||
| import com.google.inject.Inject; | ||||
| import javax.ws.rs.GET; | ||||
| import javax.ws.rs.Path; | ||||
| import javax.ws.rs.QueryParam; | ||||
| import org.glyptodon.guacamole.GuacamoleException; | ||||
| import org.glyptodon.guacamole.net.auth.UserContext; | ||||
| import org.glyptodon.guacamole.net.basic.rest.AuthProviderRESTExposure; | ||||
| import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService; | ||||
| import org.slf4j.Logger; | ||||
| import org.slf4j.LoggerFactory; | ||||
|  | ||||
| /** | ||||
|  * REST service which updates the last access time of the Guacamole session, | ||||
|  * preventing the session from becoming invalid. | ||||
|  * | ||||
|  * @author Michael Jumper | ||||
|  */ | ||||
| @Path("/keep-alive") | ||||
| public class SessionKeepAlive { | ||||
|  | ||||
|     /** | ||||
|      * A service for authenticating users from auth tokens. | ||||
|      */ | ||||
|     @Inject | ||||
|     private AuthenticationService authenticationService; | ||||
|  | ||||
|     /** | ||||
|      * Logger for this class. | ||||
|      */ | ||||
|     private final Logger logger = LoggerFactory.getLogger(SessionKeepAlive.class); | ||||
|  | ||||
|     @GET | ||||
|     @AuthProviderRESTExposure | ||||
|     public void updateSession(@QueryParam("token") String authToken) throws GuacamoleException { | ||||
|  | ||||
|         // Tickle the session | ||||
|         UserContext context = authenticationService.getUserContext(authToken); | ||||
|  | ||||
|         // Do nothing | ||||
|         logger.debug("Keep-alive signal received from user \"{}\".", context.self().getUsername()); | ||||
|          | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -25,7 +25,6 @@ package org.glyptodon.guacamole.net.basic; | ||||
| import com.google.inject.Inject; | ||||
| import com.google.inject.Singleton; | ||||
| import org.glyptodon.guacamole.net.basic.rest.clipboard.ClipboardRESTService; | ||||
| import java.util.Collection; | ||||
| import java.util.List; | ||||
| import org.glyptodon.guacamole.GuacamoleClientException; | ||||
| import org.glyptodon.guacamole.GuacamoleException; | ||||
| @@ -35,7 +34,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.Credentials; | ||||
| import org.glyptodon.guacamole.net.auth.Directory; | ||||
| import org.glyptodon.guacamole.net.auth.UserContext; | ||||
| import org.glyptodon.guacamole.net.basic.rest.auth.AuthenticationService; | ||||
| @@ -72,12 +70,10 @@ public class TunnelRequestService { | ||||
|     private AuthenticationService authenticationService; | ||||
|  | ||||
|     /** | ||||
|      * Notifies all listeners in the given collection that a tunnel has been | ||||
|      * Notifies all listeners in the given session that a tunnel has been | ||||
|      * connected. | ||||
|      * | ||||
|      * @param listeners A collection of all listeners that should be notified. | ||||
|      * @param context The UserContext associated with the current session. | ||||
|      * @param credentials The credentials associated with the current session. | ||||
|      * @param session The session associated with the listeners to be notified. | ||||
|      * @param tunnel The tunnel being connected. | ||||
|      * @return true if all listeners are allowing the tunnel to connect, | ||||
|      *         or if there are no listeners, and false if any listener is | ||||
| @@ -88,16 +84,17 @@ public class TunnelRequestService { | ||||
|      *                            error, the connect is canceled, and no other | ||||
|      *                            listeners will run. | ||||
|      */ | ||||
|     private boolean notifyConnect(Collection listeners, UserContext context, | ||||
|             Credentials credentials, GuacamoleTunnel tunnel) | ||||
|     private boolean notifyConnect(GuacamoleSession session, GuacamoleTunnel tunnel) | ||||
|             throws GuacamoleException { | ||||
|  | ||||
|         // Build event for auth success | ||||
|         TunnelConnectEvent event = new TunnelConnectEvent(context, | ||||
|                 credentials, tunnel); | ||||
|         TunnelConnectEvent event = new TunnelConnectEvent( | ||||
|                 session.getUserContext(), | ||||
|                 session.getCredentials(), | ||||
|                 tunnel); | ||||
|  | ||||
|         // Notify all listeners | ||||
|         for (Object listener : listeners) { | ||||
|         for (Object listener : session.getListeners()) { | ||||
|             if (listener instanceof TunnelConnectListener) { | ||||
|  | ||||
|                 // Cancel immediately if hook returns false | ||||
| @@ -112,12 +109,10 @@ public class TunnelRequestService { | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Notifies all listeners in the given collection that a tunnel has been | ||||
|      * Notifies all listeners in the given session that a tunnel has been | ||||
|      * closed. | ||||
|      * | ||||
|      * @param listeners A collection of all listeners that should be notified. | ||||
|      * @param context The UserContext associated with the current session. | ||||
|      * @param credentials The credentials associated with the current session. | ||||
|      * @param session The session associated with the listeners to be notified. | ||||
|      * @param tunnel The tunnel being closed. | ||||
|      * @return true if all listeners are allowing the tunnel to close, | ||||
|      *         or if there are no listeners, and false if any listener is | ||||
| @@ -128,16 +123,17 @@ public class TunnelRequestService { | ||||
|      *                            error, the close is canceled, and no other | ||||
|      *                            listeners will run. | ||||
|      */ | ||||
|     private boolean notifyClose(Collection listeners, UserContext context, | ||||
|             Credentials credentials, GuacamoleTunnel tunnel) | ||||
|     private boolean notifyClose(GuacamoleSession session, GuacamoleTunnel tunnel) | ||||
|             throws GuacamoleException { | ||||
|  | ||||
|         // Build event for auth success | ||||
|         TunnelCloseEvent event = new TunnelCloseEvent(context, | ||||
|                 credentials, tunnel); | ||||
|         TunnelCloseEvent event = new TunnelCloseEvent( | ||||
|                 session.getUserContext(), | ||||
|                 session.getCredentials(), | ||||
|                 tunnel); | ||||
|  | ||||
|         // Notify all listeners | ||||
|         for (Object listener : listeners) { | ||||
|         for (Object listener : session.getListeners()) { | ||||
|             if (listener instanceof TunnelCloseListener) { | ||||
|  | ||||
|                 // Cancel immediately if hook returns false | ||||
| @@ -165,8 +161,8 @@ public class TunnelRequestService { | ||||
|  | ||||
|         // Get auth token and session | ||||
|         String authToken = request.getParameter("authToken"); | ||||
|         GuacamoleSession session = authenticationService.getGuacamoleSession(authToken); | ||||
|          | ||||
|         final GuacamoleSession session = authenticationService.getGuacamoleSession(authToken); | ||||
|  | ||||
|         // Get ID of connection | ||||
|         String id = request.getParameter("id"); | ||||
|         TunnelRequest.IdentifierType id_type = TunnelRequest.IdentifierType.getType(id); | ||||
| @@ -178,18 +174,6 @@ public class TunnelRequestService { | ||||
|         // Remove prefix | ||||
|         id = id.substring(id_type.PREFIX.length()); | ||||
|  | ||||
|         // Get session-specific elements | ||||
|         final Credentials credentials = session.getCredentials(); | ||||
|         final UserContext context = session.getUserContext(); | ||||
|         final Collection listeners = session.getListeners(); | ||||
|          | ||||
|         // If no context or no credentials, not logged in | ||||
|         if (context == null || credentials == null) | ||||
|             throw new GuacamoleSecurityException("Cannot connect - user not logged in."); | ||||
|  | ||||
|         // Get clipboard  | ||||
|         final ClipboardState clipboard = session.getClipboardState(); | ||||
|  | ||||
|         // Get client information | ||||
|         GuacamoleClientInformation info = new GuacamoleClientInformation(); | ||||
|  | ||||
| @@ -225,6 +209,8 @@ public class TunnelRequestService { | ||||
|             // Connection identifiers | ||||
|             case CONNECTION: { | ||||
|  | ||||
|                 UserContext context = session.getUserContext(); | ||||
|  | ||||
|                 // Get connection directory | ||||
|                 Directory<String, Connection> directory = | ||||
|                     context.getRootConnectionGroup().getConnectionDirectory(); | ||||
| @@ -245,6 +231,8 @@ public class TunnelRequestService { | ||||
|             // Connection group identifiers | ||||
|             case CONNECTION_GROUP: { | ||||
|  | ||||
|                 UserContext context = session.getUserContext(); | ||||
|  | ||||
|                 // Get connection group directory | ||||
|                 Directory<String, ConnectionGroup> directory = | ||||
|                     context.getRootConnectionGroup().getConnectionGroupDirectory(); | ||||
| @@ -271,6 +259,11 @@ public class TunnelRequestService { | ||||
|         // Associate socket with tunnel | ||||
|         GuacamoleTunnel tunnel = new GuacamoleTunnel(socket) { | ||||
|  | ||||
|             /** | ||||
|              * The current clipboard state. | ||||
|              */ | ||||
|             private final ClipboardState clipboard = session.getClipboardState(); | ||||
|              | ||||
|             @Override | ||||
|             public GuacamoleReader acquireReader() { | ||||
|  | ||||
| @@ -293,9 +286,11 @@ public class TunnelRequestService { | ||||
|             public void close() throws GuacamoleException { | ||||
|  | ||||
|                 // Only close if not canceled | ||||
|                 if (!notifyClose(listeners, context, credentials, this)) | ||||
|                 if (!notifyClose(session, this)) | ||||
|                     throw new GuacamoleException("Tunnel close canceled by listener."); | ||||
|  | ||||
|                 session.removeTunnel(getUUID().toString()); | ||||
|                  | ||||
|                 // Close if no exception due to listener | ||||
|                 super.close(); | ||||
|  | ||||
| @@ -304,7 +299,7 @@ public class TunnelRequestService { | ||||
|         }; | ||||
|  | ||||
|         // Notify listeners about connection | ||||
|         if (!notifyConnect(listeners, context, credentials, tunnel)) { | ||||
|         if (!notifyConnect(session, tunnel)) { | ||||
|             logger.info("Successful connection canceled by hook."); | ||||
|             return null; | ||||
|         } | ||||
|   | ||||
| @@ -26,7 +26,6 @@ import com.google.inject.Scopes; | ||||
| import com.google.inject.servlet.ServletModule; | ||||
| import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; | ||||
| import org.codehaus.jackson.jaxrs.JacksonJsonProvider; | ||||
| import org.glyptodon.guacamole.net.basic.SessionKeepAlive; | ||||
| import org.glyptodon.guacamole.net.basic.rest.auth.LoginRESTService; | ||||
| import org.glyptodon.guacamole.net.basic.rest.clipboard.ClipboardRESTService; | ||||
| import org.glyptodon.guacamole.net.basic.rest.connection.ConnectionRESTService; | ||||
| @@ -51,7 +50,6 @@ public class RESTServletModule extends ServletModule { | ||||
|         bind(ConnectionGroupRESTService.class); | ||||
|         bind(PermissionRESTService.class); | ||||
|         bind(ProtocolRESTService.class); | ||||
|         bind(SessionKeepAlive.class); | ||||
|         bind(UserRESTService.class); | ||||
|         bind(LoginRESTService.class); | ||||
|          | ||||
|   | ||||
| @@ -104,8 +104,16 @@ public class BasicTokenSessionMap implements TokenSessionMap { | ||||
|      * @param authToken The auth token for the session. | ||||
|      * @return True if the session has timed out, false otherwise. | ||||
|      */ | ||||
|     private boolean sessionHasTimedOut(String authToken) { | ||||
|     private boolean isSessionActive(String authToken) { | ||||
|  | ||||
|         GuacamoleSession session = sessionMap.get(authToken); | ||||
|         if (session == null) | ||||
|             return false; | ||||
|  | ||||
|         // A session is active if it has any active tunnels | ||||
|         if (session.hasTunnels()) | ||||
|             return true; | ||||
|          | ||||
|         if (!lastAccessTimeMap.containsKey(authToken)) | ||||
|             return true; | ||||
|          | ||||
| @@ -120,7 +128,7 @@ public class BasicTokenSessionMap implements TokenSessionMap { | ||||
|     public GuacamoleSession get(String authToken) { | ||||
|          | ||||
|         // If the session has timed out, evict the token and force the user to log in again | ||||
|         if (sessionHasTimedOut(authToken)) { | ||||
|         if (isSessionActive(authToken)) { | ||||
|             evict(authToken); | ||||
|             return null; | ||||
|         } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user