From a3faf6a2eeb0955fede6db74156d51df22da4a39 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Tue, 29 May 2018 22:13:04 -0400 Subject: [PATCH] GUACAMOLE-566: Handle all exceptions, not just GuacamoleException instances. --- ...onMapper.java => RESTExceptionMapper.java} | 57 +++++++++++-------- .../guacamole/rest/RESTServiceModule.java | 4 +- 2 files changed, 34 insertions(+), 27 deletions(-) rename guacamole/src/main/java/org/apache/guacamole/rest/{GuacamoleExceptionMapper.java => RESTExceptionMapper.java} (63%) diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java b/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionMapper.java similarity index 63% rename from guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java rename to guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionMapper.java index dd8c76ee3..ae352747b 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionMapper.java @@ -21,18 +21,12 @@ package org.apache.guacamole.rest; import com.google.inject.Inject; import com.google.inject.Singleton; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.Map; import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.FormParam; -import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.ext.ExceptionMapper; import javax.ws.rs.ext.Provider; -import org.aopalliance.intercept.MethodInvocation; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleUnauthorizedException; import org.apache.guacamole.rest.auth.AuthenticationService; @@ -46,18 +40,18 @@ import org.slf4j.LoggerFactory; */ @Provider @Singleton -public class GuacamoleExceptionMapper - implements ExceptionMapper { +public class RESTExceptionMapper implements ExceptionMapper { /** * The logger for this class. */ - private final Logger logger = LoggerFactory.getLogger(GuacamoleExceptionMapper.class); + private final Logger logger = LoggerFactory.getLogger(RESTExceptionMapper.class); /** * The request associated with this instance of this mapper. */ - @Context private HttpServletRequest request; + @Context + private HttpServletRequest request; /** * The authentication service associated with the currently active session. @@ -75,37 +69,50 @@ public class GuacamoleExceptionMapper */ private String getAuthenticationToken() { - @SuppressWarnings("unchecked") - Map parameters = request.getParameterMap(); - - for (String paramName : parameters.keySet()) { - if (paramName.equals("token")) { - String tokenParams[] = parameters.get(paramName); - if (tokenParams[0] != null && !tokenParams[0].isEmpty()) - return tokenParams[0]; - } - } + String token = request.getParameter("token"); + if (token != null && !token.isEmpty()) + return token; return null; } @Override - public Response toResponse(GuacamoleException e) { + public Response toResponse(Throwable t) { - if (e instanceof GuacamoleUnauthorizedException) { + // Ensure any associated session is invalidated if unauthorized + if (t instanceof GuacamoleUnauthorizedException) { String token = getAuthenticationToken(); if (authenticationService.destroyGuacamoleSession(token)) logger.debug("Implicitly invalidated session for token \"{}\"", token); } + // Translate GuacamoleException subclasses to HTTP error codes + if (t instanceof GuacamoleException) + return Response + .status(((GuacamoleException) t).getHttpStatusCode()) + .entity(new APIError((GuacamoleException)t)) + .type(MediaType.APPLICATION_JSON) + .build(); + + // Rethrow unchecked exceptions such that they are properly wrapped + String message = t.getMessage(); + if (message != null) + logger.error("Unexpected internal error: {}", message); + else + logger.error("An internal error occurred, but did not contain " + + "an error message. Enable debug-level logging for " + + "details."); + + logger.debug("Unexpected error in REST endpoint.", t); + return Response - .status(e.getHttpStatusCode()) - .entity(new APIError(e)) + .status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Unexpected Internal Error.") .type(MediaType.APPLICATION_JSON) .build(); - + } } \ No newline at end of file diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java b/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java index 8075b1e68..b23eec6b0 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java @@ -84,8 +84,8 @@ public class RESTServiceModule extends ServletModule { bind(AuthTokenGenerator.class).to(SecureRandomAuthTokenGenerator.class); bind(DecorationService.class); - // Get the ExceptionMapper that will rewrite exceptions into JSON. - bind(GuacamoleExceptionMapper.class); + // Automatically translate GuacamoleExceptions for REST methods + bind(RESTExceptionMapper.class); // Set up the API endpoints bind(ExtensionRESTService.class);