GUACAMOLE-956: Provide alternative means of deleting the current token that does not specify the token within the URL.

This commit is contained in:
Michael Jumper
2021-02-26 13:15:46 -08:00
parent aacf63857c
commit 1a0802f4a3
4 changed files with 59 additions and 13 deletions

View File

@@ -264,10 +264,10 @@ angular.module('auth').factory('authenticationService', ['$injector',
* A promise which succeeds only if the token was successfully revoked. * A promise which succeeds only if the token was successfully revoked.
*/ */
service.revokeToken = function revokeToken(token) { service.revokeToken = function revokeToken(token) {
return requestService({ return service.request({
method: 'DELETE', method: 'DELETE',
url: 'api/tokens/' + token url: 'api/session'
}); }, token);
}; };
/** /**
@@ -303,7 +303,7 @@ angular.module('auth').factory('authenticationService', ['$injector',
* successful. * successful.
*/ */
service.logout = function logout() { service.logout = function logout() {
// Clear authentication data // Clear authentication data
var token = service.getCurrentToken(); var token = service.getCurrentToken();
clearAuthenticationResult(); clearAuthenticationResult();
@@ -411,25 +411,33 @@ angular.module('auth').factory('authenticationService', ['$injector',
/** /**
* Makes an HTTP request leveraging the requestService(), automatically * Makes an HTTP request leveraging the requestService(), automatically
* including the user's authentication token using the "Guacamole-Token" * including the given authentication token using the "Guacamole-Token"
* header. If the user is not logged in, the "Guacamole-Token" header is * header. If no token is provided, the user's current authentication token
* simply omitted. The provided configuration object is not modified by * is used instead. If the user is not logged in, the "Guacamole-Token"
* this function. * header is simply omitted. The provided configuration object is not
* modified by this function.
* *
* @param {Object} object * @param {Object} object
* A configuration object describing the HTTP request to be made by * A configuration object describing the HTTP request to be made by
* requestService(). As described by requestService(), this object must * requestService(). As described by requestService(), this object must
* be a configuration object accepted by AngularJS' $http service. * be a configuration object accepted by AngularJS' $http service.
* *
* @param {string} [token]
* The authentication token to pass with the "Guacamole-Token" header.
* If omitted, and the user is logged in, the user's current
* authentication token will be used.
*
* @returns {Promise.<Object>} * @returns {Promise.<Object>}
* A promise that will resolve with the data from the HTTP response for * A promise that will resolve with the data from the HTTP response for
* the underlying requestService() call if successful, or reject with * the underlying requestService() call if successful, or reject with
* an @link{Error} describing the failure. * an @link{Error} describing the failure.
*/ */
service.request = function request(object) { service.request = function request(object, token) {
// Attempt to use current token if none is provided
token = token || service.getCurrentToken();
// Add "Guacamole-Token" header if an authentication token is available // Add "Guacamole-Token" header if an authentication token is available
var token = service.getCurrentToken();
if (token) { if (token) {
object = _.merge({ object = _.merge({
headers : { 'Guacamole-Token' : token } headers : { 'Guacamole-Token' : token }

View File

@@ -72,7 +72,7 @@ public class SessionRESTService {
// Return a resource exposing the retrieved session // Return a resource exposing the retrieved session
GuacamoleSession session = authenticationService.getGuacamoleSession(authToken); GuacamoleSession session = authenticationService.getGuacamoleSession(authToken);
return sessionResourceFactory.create(session); return sessionResourceFactory.create(authToken, session);
} }

View File

@@ -23,6 +23,7 @@ import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject; import com.google.inject.assistedinject.AssistedInject;
import javax.inject.Inject; import javax.inject.Inject;
import javax.ws.rs.Consumes; import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
@@ -31,6 +32,7 @@ import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleResourceNotFoundException; import org.apache.guacamole.GuacamoleResourceNotFoundException;
import org.apache.guacamole.GuacamoleSession; import org.apache.guacamole.GuacamoleSession;
import org.apache.guacamole.net.auth.UserContext; import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.rest.auth.AuthenticationService;
import org.apache.guacamole.rest.tunnel.TunnelCollectionResource; import org.apache.guacamole.rest.tunnel.TunnelCollectionResource;
import org.apache.guacamole.rest.tunnel.TunnelCollectionResourceFactory; import org.apache.guacamole.rest.tunnel.TunnelCollectionResourceFactory;
@@ -47,6 +49,18 @@ public class SessionResource {
*/ */
private final GuacamoleSession session; private final GuacamoleSession session;
/**
* The authentication token associated with the GuacamoleSession being
* exposed by this SessionResource.
*/
private final String token;
/**
* Service for authenticating users and managing their Guacamole sessions.
*/
@Inject
private AuthenticationService authenticationService;
/** /**
* Factory for creating UserContextResources which expose a given * Factory for creating UserContextResources which expose a given
* UserContext. * UserContext.
@@ -65,12 +79,16 @@ public class SessionResource {
* Creates a new SessionResource which exposes the data within the given * Creates a new SessionResource which exposes the data within the given
* GuacamoleSession. * GuacamoleSession.
* *
* @param token
* The authentication token associated with the given session.
*
* @param session * @param session
* The GuacamoleSession which should be exposed through this * The GuacamoleSession which should be exposed through this
* SessionResource. * SessionResource.
*/ */
@AssistedInject @AssistedInject
public SessionResource(@Assisted GuacamoleSession session) { public SessionResource(@Assisted String token, @Assisted GuacamoleSession session) {
this.token = token;
this.session = session; this.session = session;
} }
@@ -149,4 +167,21 @@ public class SessionResource {
return tunnelCollectionResourceFactory.create(session); return tunnelCollectionResourceFactory.create(session);
} }
/**
* Invalidates the GuacamoleSession exposed by this SessionResource,
* including the associated authentication token.
*
* @throws GuacamoleException
* If the authentication token originally provided when this
* SessionResource was created no longer exists.
*/
@DELETE
public void invalidate() throws GuacamoleException {
// Invalidate session, if it exists
if (!authenticationService.destroyGuacamoleSession(token))
throw new GuacamoleResourceNotFoundException("No such token.");
}
} }

View File

@@ -31,6 +31,9 @@ public interface SessionResourceFactory {
* Creates a new SessionResource which exposes the contents of the * Creates a new SessionResource which exposes the contents of the
* given GuacamoleSession. * given GuacamoleSession.
* *
* @param token
* The authentication token associated with the given session.
*
* @param session * @param session
* The GuacamoleSession whose contents should be exposed. * The GuacamoleSession whose contents should be exposed.
* *
@@ -38,6 +41,6 @@ public interface SessionResourceFactory {
* A new SessionResource which exposes the contents of the given * A new SessionResource which exposes the contents of the given
* GuacamoleSession. * GuacamoleSession.
*/ */
SessionResource create(GuacamoleSession session); SessionResource create(String token, GuacamoleSession session);
} }