From a60377486552176a745e5000c70658a4c96f678b Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Mon, 28 May 2018 21:05:11 -0400 Subject: [PATCH 1/8] GUACAMOLE-566: Implement GuacamoleExceptionMapper to deal with exceptions thrown in REST APIs in extensions. --- .../guacamole/extension/ExtensionModule.java | 4 ++ .../rest/GuacamoleExceptionMapper.java | 54 +++++++++++++++++++ .../guacamole/rest/RESTExceptionWrapper.java | 3 -- .../guacamole/rest/RESTServiceModule.java | 3 ++ 4 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java index 524ff5789..665c02881 100644 --- a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java +++ b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java @@ -39,6 +39,7 @@ import org.apache.guacamole.resource.Resource; import org.apache.guacamole.resource.ResourceServlet; import org.apache.guacamole.resource.SequenceResource; import org.apache.guacamole.resource.WebApplicationResource; +import org.apache.guacamole.rest.GuacamoleExceptionMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -418,6 +419,9 @@ public class ExtensionModule extends ServletModule { bind(LanguageResourceService.class).toInstance(languageResourceService); bind(PatchResourceService.class).toInstance(patchResourceService); + // Get ExceptionMapper to rewrite exceptions in JSON. + bind(GuacamoleExceptionMapper.class); + // Load initial language resources from servlet context languageResourceService.addLanguageResources(getServletContext()); diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java b/guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java new file mode 100644 index 000000000..4af39b8fa --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.guacamole.rest; + +import com.google.inject.Singleton; +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.apache.guacamole.GuacamoleException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A class that maps GuacamoleExceptions in a way that returns a + * custom response to the user via JSON rather than allowing the default + * web application error handling to take place. + */ +@Provider +@Singleton +public class GuacamoleExceptionMapper + implements ExceptionMapper { + + private final Logger logger = LoggerFactory.getLogger(GuacamoleExceptionMapper.class); + + @Override + public Response toResponse(GuacamoleException e) { + logger.debug(">>>EXMAPPER<<< Mapping exception {}", e.getMessage()); + return Response + .status(e.getHttpStatusCode()) + .entity(new APIError(e)) + .type(MediaType.APPLICATION_JSON) + .build(); + + } + +} \ No newline at end of file diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionWrapper.java b/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionWrapper.java index a0c756ebe..fb854b041 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionWrapper.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionWrapper.java @@ -28,10 +28,7 @@ import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Response; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; -import org.apache.guacamole.GuacamoleClientException; import org.apache.guacamole.GuacamoleException; -import org.apache.guacamole.GuacamoleResourceNotFoundException; -import org.apache.guacamole.GuacamoleSecurityException; import org.apache.guacamole.GuacamoleUnauthorizedException; import org.apache.guacamole.rest.auth.AuthenticationService; import org.slf4j.Logger; 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 b326fa534..cfa8b063a 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java @@ -88,6 +88,9 @@ public class RESTServiceModule extends ServletModule { MethodInterceptor interceptor = new RESTExceptionWrapper(); requestInjection(interceptor); bindInterceptor(Matchers.any(), new RESTMethodMatcher(), interceptor); + + // Get the ExceptionMapper that will rewrite exceptions into JSON. + bind(GuacamoleExceptionMapper.class); // Set up the API endpoints bind(ExtensionRESTService.class); From eb91f4d87a408ff82a308fe9f45069771d5ba1aa Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Tue, 29 May 2018 17:24:54 -0400 Subject: [PATCH 2/8] GUACAMOLE-566: Replace the entire RESTExceptionWrapper with the ExceptionMapper implementation. --- .../guacamole/extension/ExtensionModule.java | 6 +- .../rest/GuacamoleExceptionMapper.java | 60 +++++- .../guacamole/rest/RESTExceptionWrapper.java | 200 ------------------ .../guacamole/rest/RESTServiceModule.java | 5 - 4 files changed, 60 insertions(+), 211 deletions(-) delete mode 100644 guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionWrapper.java diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java index 665c02881..822741c1a 100644 --- a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java +++ b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java @@ -39,7 +39,6 @@ import org.apache.guacamole.resource.Resource; import org.apache.guacamole.resource.ResourceServlet; import org.apache.guacamole.resource.SequenceResource; import org.apache.guacamole.resource.WebApplicationResource; -import org.apache.guacamole.rest.GuacamoleExceptionMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -418,10 +417,7 @@ public class ExtensionModule extends ServletModule { // Bind resource services bind(LanguageResourceService.class).toInstance(languageResourceService); bind(PatchResourceService.class).toInstance(patchResourceService); - - // Get ExceptionMapper to rewrite exceptions in JSON. - bind(GuacamoleExceptionMapper.class); - + // Load initial language resources from servlet context languageResourceService.addLanguageResources(getServletContext()); diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java b/guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java index 4af39b8fa..f27c59c07 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java @@ -19,12 +19,23 @@ 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; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,12 +48,59 @@ import org.slf4j.LoggerFactory; @Singleton public class GuacamoleExceptionMapper implements ExceptionMapper { - + + /** + * The logger for this class. + */ private final Logger logger = LoggerFactory.getLogger(GuacamoleExceptionMapper.class); + /** + * The request associated with this instance of this mapper. + */ + @Context private HttpServletRequest request; + + /** + * The authentication service associated with the currently active session. + */ + @Inject + private AuthenticationService authenticationService; + + /** + * Returns the authentication token that is in use in the current session, + * if present, or null if otherwise. + * + * @return + * The authentication token for the current session, or null if no + * token is present. + */ + 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]; + } + } + + return null; + + } + @Override public Response toResponse(GuacamoleException e) { logger.debug(">>>EXMAPPER<<< Mapping exception {}", e.getMessage()); + + if (e instanceof GuacamoleUnauthorizedException) { + String token = getAuthenticationToken(); + + if (authenticationService.destroyGuacamoleSession(token)) + logger.debug("Implicitly invalidated session for token \"{}\"", token); + } + return Response .status(e.getHttpStatusCode()) .entity(new APIError(e)) diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionWrapper.java b/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionWrapper.java deleted file mode 100644 index fb854b041..000000000 --- a/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionWrapper.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package org.apache.guacamole.rest; - -import com.google.inject.Inject; -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import javax.ws.rs.FormParam; -import javax.ws.rs.QueryParam; -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.Response; -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; -import org.apache.guacamole.GuacamoleException; -import org.apache.guacamole.GuacamoleUnauthorizedException; -import org.apache.guacamole.rest.auth.AuthenticationService; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A method interceptor which wraps custom exception handling around methods - * which can throw GuacamoleExceptions and which are exposed through the REST - * interface. The various types of GuacamoleExceptions are automatically - * translated into appropriate HTTP responses, including JSON describing the - * error that occurred. - */ -public class RESTExceptionWrapper implements MethodInterceptor { - - /** - * Logger for this class. - */ - private final Logger logger = LoggerFactory.getLogger(RESTExceptionWrapper.class); - - /** - * Service for authenticating users and managing their Guacamole sessions. - */ - @Inject - private AuthenticationService authenticationService; - - /** - * Determines whether the given set of annotations describes an HTTP - * request parameter of the given name. For a parameter to be associated - * with an HTTP request parameter, it must be annotated with either the - * @QueryParam or @FormParam annotations. - * - * @param annotations - * The annotations associated with the Java parameter being checked. - * - * @param name - * The name of the HTTP request parameter. - * - * @return - * true if the given set of annotations describes an HTTP request - * parameter having the given name, false otherwise. - */ - private boolean isRequestParameter(Annotation[] annotations, String name) { - - // Search annotations for associated HTTP parameters - for (Annotation annotation : annotations) { - - // Check if parameter is associated with the HTTP query string - if (annotation instanceof QueryParam && name.equals(((QueryParam) annotation).value())) - return true; - - // Failing that, check whether the parameter is associated with the - // HTTP request body - if (annotation instanceof FormParam && name.equals(((FormParam) annotation).value())) - return true; - - } - - // No parameter annotations are present - return false; - - } - - /** - * Returns the authentication token that was passed in the given method - * invocation. If the given method invocation is not associated with an - * HTTP request (it lacks the appropriate JAX-RS annotations) or there is - * no authentication token, null is returned. - * - * @param invocation - * The method invocation whose corresponding authentication token - * should be determined. - * - * @return - * The authentication token passed in the given method invocation, or - * null if there is no such token. - */ - private String getAuthenticationToken(MethodInvocation invocation) { - - Method method = invocation.getMethod(); - - // Get the types and annotations associated with each parameter - Annotation[][] parameterAnnotations = method.getParameterAnnotations(); - Class[] parameterTypes = method.getParameterTypes(); - - // The Java standards require these to be parallel arrays - assert(parameterAnnotations.length == parameterTypes.length); - - // Iterate through all parameters, looking for the authentication token - for (int i = 0; i < parameterTypes.length; i++) { - - // Only inspect String parameters - Class parameterType = parameterTypes[i]; - if (parameterType != String.class) - continue; - - // Parameter must be declared as a REST service parameter - Annotation[] annotations = parameterAnnotations[i]; - if (!isRequestParameter(annotations, "token")) - continue; - - // The token parameter has been found - return its value - Object[] args = invocation.getArguments(); - return (String) args[i]; - - } - - // No token parameter is defined - return null; - - } - - @Override - public Object invoke(MethodInvocation invocation) throws WebApplicationException { - - try { - - // Invoke wrapped method - try { - return invocation.proceed(); - } - - // Ensure any associated session is invalidated if unauthorized - catch (GuacamoleUnauthorizedException e) { - - // Pull authentication token from request - String token = getAuthenticationToken(invocation); - - // If there is an associated auth token, invalidate it - if (authenticationService.destroyGuacamoleSession(token)) - logger.debug("Implicitly invalidated session for token \"{}\".", token); - - // Continue with exception processing - throw e; - - } - - } - - // Translate GuacamoleException subclasses to HTTP error codes - catch (GuacamoleException e) { - throw new APIException( - Response.Status.fromStatusCode(e.getHttpStatusCode()), - e - ); - } - - // Rethrow unchecked exceptions such that they are properly wrapped - catch (Throwable t) { - - // Log all reasonable details of error - 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."); - - // Ensure internal errors are fully logged at the debug level - logger.debug("Unexpected error in REST endpoint.", t); - - throw new APIException(Response.Status.INTERNAL_SERVER_ERROR, - new GuacamoleException("Unexpected internal error.", t)); - - } - - } - -} 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 cfa8b063a..8075b1e68 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java @@ -83,11 +83,6 @@ public class RESTServiceModule extends ServletModule { bind(AuthenticationService.class); bind(AuthTokenGenerator.class).to(SecureRandomAuthTokenGenerator.class); bind(DecorationService.class); - - // Automatically translate GuacamoleExceptions for REST methods - MethodInterceptor interceptor = new RESTExceptionWrapper(); - requestInjection(interceptor); - bindInterceptor(Matchers.any(), new RESTMethodMatcher(), interceptor); // Get the ExceptionMapper that will rewrite exceptions into JSON. bind(GuacamoleExceptionMapper.class); From 399f7e15adbf9e187b499068118a072f2a97a300 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Tue, 29 May 2018 18:00:44 -0400 Subject: [PATCH 3/8] GUACAMOLE-566: Remove debug code. --- .../java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java | 1 - 1 file changed, 1 deletion(-) diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java b/guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java index f27c59c07..dd8c76ee3 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/GuacamoleExceptionMapper.java @@ -92,7 +92,6 @@ public class GuacamoleExceptionMapper @Override public Response toResponse(GuacamoleException e) { - logger.debug(">>>EXMAPPER<<< Mapping exception {}", e.getMessage()); if (e instanceof GuacamoleUnauthorizedException) { String token = getAuthenticationToken(); From 75c8fc856b1f6c1d9b3fb7b69b9128add4f1cda3 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Tue, 29 May 2018 18:01:54 -0400 Subject: [PATCH 4/8] GUACAMOLE-566: Remove silly unnecessary space. --- .../java/org/apache/guacamole/extension/ExtensionModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java index 822741c1a..524ff5789 100644 --- a/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java +++ b/guacamole/src/main/java/org/apache/guacamole/extension/ExtensionModule.java @@ -417,7 +417,7 @@ public class ExtensionModule extends ServletModule { // Bind resource services bind(LanguageResourceService.class).toInstance(languageResourceService); bind(PatchResourceService.class).toInstance(patchResourceService); - + // Load initial language resources from servlet context languageResourceService.addLanguageResources(getServletContext()); From a3faf6a2eeb0955fede6db74156d51df22da4a39 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Tue, 29 May 2018 22:13:04 -0400 Subject: [PATCH 5/8] 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); From 383a71723af1870fc0ae2a0f0f4f9002c8e63b69 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Tue, 29 May 2018 22:14:55 -0400 Subject: [PATCH 6/8] GUACAMOLE-566: Remove another extra set of spaces. --- .../main/java/org/apache/guacamole/rest/RESTServiceModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b23eec6b0..4efab0ff5 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/RESTServiceModule.java @@ -83,7 +83,7 @@ public class RESTServiceModule extends ServletModule { bind(AuthenticationService.class); bind(AuthTokenGenerator.class).to(SecureRandomAuthTokenGenerator.class); bind(DecorationService.class); - + // Automatically translate GuacamoleExceptions for REST methods bind(RESTExceptionMapper.class); From 6cb50bd4f8ea47ec1f2fb6ff79c6aceeb83c84e0 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Wed, 30 May 2018 06:27:21 -0400 Subject: [PATCH 7/8] GUACAMOLE-566: Minor style cleanups; use APIError for unhandled exceptions. --- .../java/org/apache/guacamole/rest/RESTExceptionMapper.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionMapper.java b/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionMapper.java index ae352747b..931408d6f 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionMapper.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionMapper.java @@ -92,7 +92,7 @@ public class RESTExceptionMapper implements ExceptionMapper { if (t instanceof GuacamoleException) return Response .status(((GuacamoleException) t).getHttpStatusCode()) - .entity(new APIError((GuacamoleException)t)) + .entity(new APIError((GuacamoleException) t)) .type(MediaType.APPLICATION_JSON) .build(); @@ -109,7 +109,8 @@ public class RESTExceptionMapper implements ExceptionMapper { return Response .status(Response.Status.INTERNAL_SERVER_ERROR) - .entity("Unexpected Internal Error.") + .entity(new APIError( + new GuacamoleException("Unexpected internal error", t))) .type(MediaType.APPLICATION_JSON) .build(); From 7abf9f2f5d86b3c6d9296eaeca6e695e1b500851 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Thu, 31 May 2018 16:20:40 -0400 Subject: [PATCH 8/8] GUACAMOLE-566: Update comment for request object in new mapper class. --- .../java/org/apache/guacamole/rest/RESTExceptionMapper.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionMapper.java b/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionMapper.java index 931408d6f..91179473a 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionMapper.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/RESTExceptionMapper.java @@ -48,7 +48,9 @@ public class RESTExceptionMapper implements ExceptionMapper { private final Logger logger = LoggerFactory.getLogger(RESTExceptionMapper.class); /** - * The request associated with this instance of this mapper. + * The HttpServletRequest for the Throwable being intercepted. Despite this + * class being a Singleton, this object will always be scoped with the + * current request for the Throwable that is being processed by this class. */ @Context private HttpServletRequest request;