GUACAMOLE-1224: Add user session invalidation/logout event.

This commit is contained in:
Michael Jumper
2022-10-02 11:58:32 -07:00
parent 63de886e5d
commit b3319b817d
5 changed files with 67 additions and 18 deletions

View File

@@ -23,12 +23,13 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.net.GuacamoleTunnel;
import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticationProvider;
import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.net.event.UserSessionInvalidatedEvent;
import org.apache.guacamole.rest.auth.DecoratedUserContext;
import org.apache.guacamole.rest.event.ListenerService;
import org.apache.guacamole.tunnel.UserTunnel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -58,8 +59,12 @@ public class GuacamoleSession {
/**
* All currently-active tunnels, indexed by tunnel UUID.
*/
private final Map<String, UserTunnel> tunnels =
new ConcurrentHashMap<String, UserTunnel>();
private final Map<String, UserTunnel> tunnels = new ConcurrentHashMap<>();
/**
* Service for dispatching events to registered event listeners.
*/
private final ListenerService listenerService;
/**
* The last time this session was accessed.
@@ -70,9 +75,9 @@ public class GuacamoleSession {
* Creates a new Guacamole session associated with the given
* AuthenticatedUser and UserContexts.
*
* @param environment
* The environment of the Guacamole server associated with this new
* session.
* @param listenerService
* The service to use to notify registered event listeners when this
* session is invalidated.
*
* @param authenticatedUser
* The authenticated user to associate this session with.
@@ -83,11 +88,12 @@ public class GuacamoleSession {
* @throws GuacamoleException
* If an error prevents the session from being created.
*/
public GuacamoleSession(Environment environment,
public GuacamoleSession(ListenerService listenerService,
AuthenticatedUser authenticatedUser,
List<DecoratedUserContext> userContexts)
throws GuacamoleException {
this.lastAccessedTime = System.currentTimeMillis();
this.listenerService = listenerService;
this.authenticatedUser = authenticatedUser;
this.userContexts = userContexts;
}
@@ -260,6 +266,23 @@ public class GuacamoleSession {
// Invalidate the authenticated user object
authenticatedUser.invalidate();
// Advise any registered listeners that the user's session is now
// invalidated
try {
listenerService.handleEvent(new UserSessionInvalidatedEvent() {
@Override
public AuthenticatedUser getAuthenticatedUser() {
return authenticatedUser;
}
});
}
catch (GuacamoleException e) {
logger.error("An extension listening for session invalidation failed: {}", e.getMessage());
logger.debug("Extension failed internally while handling the session invalidation event.", e);
}
}
}

View File

@@ -27,6 +27,7 @@ import org.apache.guacamole.net.event.ApplicationStartedEvent;
import org.apache.guacamole.net.event.DirectoryEvent;
import org.apache.guacamole.net.event.DirectoryFailureEvent;
import org.apache.guacamole.net.event.DirectorySuccessEvent;
import org.apache.guacamole.net.event.UserSessionInvalidatedEvent;
import org.apache.guacamole.net.event.listener.Listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -123,6 +124,11 @@ public class EventLoggingListener implements Listener {
else if (event instanceof DirectoryFailureEvent)
logFailure((DirectoryFailureEvent<?>) event);
// Logout / session expiration
else if (event instanceof UserSessionInvalidatedEvent)
logger.info("{} has logged out, or their session has expired or "
+ "been terminated.", new RequestingUser((UserSessionInvalidatedEvent) event));
// Application startup/shutdown
else if (event instanceof ApplicationStartedEvent)
logger.info("The Apache Guacamole web application has started.");

View File

@@ -20,7 +20,7 @@
package org.apache.guacamole.event;
import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.event.DirectoryEvent;
import org.apache.guacamole.net.event.UserEvent;
/**
* Loggable representation of the user that requested an operation.
@@ -30,7 +30,7 @@ public class RequestingUser implements LoggableDetail {
/**
* The event representing the requested operation.
*/
private final DirectoryEvent<?> event;
private final UserEvent event;
/**
* Creates a new RequestingUser that represents the user that requested the
@@ -39,7 +39,7 @@ public class RequestingUser implements LoggableDetail {
* @param event
* The event representing the requested operation.
*/
public RequestingUser(DirectoryEvent<?> event) {
public RequestingUser(UserEvent event) {
this.event = event;
}

View File

@@ -30,7 +30,6 @@ import org.apache.guacamole.GuacamoleSecurityException;
import org.apache.guacamole.GuacamoleServerException;
import org.apache.guacamole.GuacamoleUnauthorizedException;
import org.apache.guacamole.GuacamoleSession;
import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticationProvider;
import org.apache.guacamole.net.auth.Credentials;
@@ -56,12 +55,6 @@ public class AuthenticationService {
*/
private static final Logger logger = LoggerFactory.getLogger(AuthenticationService.class);
/**
* The Guacamole server environment.
*/
@Inject
private Environment environment;
/**
* All configured authentication providers which can be used to
* authenticate users or retrieve data associated with authenticated users.
@@ -443,7 +436,7 @@ public class AuthenticationService {
// If no existing session, generate a new token/session pair
else {
authToken = authTokenGenerator.getToken();
tokenSessionMap.put(authToken, new GuacamoleSession(environment, authenticatedUser, userContexts));
tokenSessionMap.put(authToken, new GuacamoleSession(listenerService, authenticatedUser, userContexts));
logger.debug("Login was successful for user \"{}\".", authenticatedUser.getIdentifier());
}